Update.
1997-05-29 12:48 Ulrich Drepper <drepper@cygnus.com> * io/ftw.c: Complete rewrite. Add implementation of `nftw'. * io/ftw.h: Update for new implementation and XPG4.2. * login/Makefile: Update for UTMP daemon implementation. Update resolver code to bind-4.9.6-T1A. * resolv/Banner: Update. * nss/digits_dots.c: Adapt text address matching to T1A. * nss/nss_files/files-hosts.c: Always use inet_pton. * resolv/base64.c (b64_pton): Follow T1A but don't use this code since it would lead to warnings. * resolv/gethnamaddr.c (getanswer): Test host name for maximal length at several places. * resolv/inet_net_pton.c (inet_net_pton_ipv4): Correct typo in comment. * resolv/res_comp.c (dn_expand): Check for overflow. (dn_comp): Likewise. * resolv/res_debug.c (precsize_aton): Better implementation. * resolv/res_init.c (res_init): Make `buf' of size MAXDNAME. * resolv/res_send.c (res_send): Check for overflow in descriptor set. * resolv/nss_dns/dns-host.c (getanswer_r): Test host name for maximal length at several places. 1997-05-29 12:51 Mark Kettenis <kettenis@phys.uva.nl> * login/utmp-private.h (struct utfuncs): Add one more parameter to updwtmp function. Declare all three function jump tables. * login/utmp.h: Declare __utmpname. * login/getutent_r.c: Remove db backend and provide support for utmpd backend. * login/login.c: Use `updwtmp' function insteead of writing the record ourself. * login/logwtmp.c: Move `updwtmp' function to... * login/updwtmp.c: ...here. New file. * login/utmp_db.h: Removed. * login/utmp_file.c: Add updwtmp function to write to file. * login/utmp_daemon.c: New file. Daemon backend. * login/utmpname.c: New file. Implementation of utmpname function. * login/utmpdump.c: New file. Tool to dump utmp-like files. * login/utmpd/connection.c: New file. * login/utmpd/database.c: New file. * login/utmpd/error.c: New file. * login/utmpd/request.c: New file. * login/utmpd/utmpd-private.h: New file. * login/utmpd/utmpd.c: New file. * login/utmpd/utmpd.h: New file. * login/utmpd/xtmp.c: New file. * login/utmpd/xtmp.h: New file. 1997-05-29 12:28 Jim Meyering <meyering@eng.ascend.com> * time/strftime.c: Correct/normalize indentation in cpp directives. 1997-05-28 20:43 Philip Blundell <pjb27@cam.ac.uk> * nis/nis_error.c: Include <string.h> to fix warning. * nis/nis_print.c: Likewise. * nis/nss_nisplus/nisplus-hosts.c: Arg 3 of map_v4v6_hostent is int* not size_t*. 1997-05-28 21:56 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/cmathcalls.h: Correct typo in comment. * inet/netinet/icmp6.h: Include <netinet/in.h> for in6_addr. * sysdeps/unix/sysv/linux/netinet/ip_fw.h: Include <net/if.h> for IFNAMSIZ. * sysdeps/unix/sysv/linux/net/ppp_defs.h: Include <time.h> for time_t. * login/pty.h: Include <ioctl-types.h> for definition of struct winsize. * misc/regexp.h (compile): Correct typo. * argp/argp.h: Put extern before __const in defintion of argp_program_bug_address. 1997-05-29 00:20 Ulrich Drepper <drepper@cygnus.com> * sysdeps/wordsize-32/inttypes.h: Correct names of unsigned fast and least types. Correct names of ?INT_FAST*_{MIN,MAX} macros. * sysdeps/wordsize-64/inttypes.h: Likewise. Reported by Andreas Jaeger <aj@arthur.rhein-neckar.de>. 1997-05-28 22:51 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/Makefile (make-ioctls-CFLAGS): Use generic ttydefaults.h file instead of non-existing version in termios/sys. Reported by Zack Weinberg <zack@rabi.phys.columbia.edu>. * time/strptime.c (strptime_internal, case 'Y'): Restrict year number to four digits and to representable range for 4 byte time_t values. Patch by H.J. Lu <hjl@lucon.org>. 1997-05-28 18:19 Philip Blundell <pjb27@cam.ac.uk> * posix/execl.c: Include <alloca.h> to avoid warning. 1997-05-27 18:19 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/libm-test.c: Implement testing of inlined functions, make output nicer, update comments. * math/test-idouble.c: New file. Frontend for double tests of inlined functions. * math/test-ildoubl.c: New file. Frontend for long double tests of inlined functions. * math/test-ifloat.c: New file. Frontend for float tests of inlined functions. * math/test-longdouble.c: Rename to... * math/test-ldouble.c: ...this. * math/Makefile: Add rules for new test programs, change rules for renaming of longdouble test. 1997-05-20 15:50 H.J. Lu <hjl@gnu.ai.mit.edu> * sunrpc/rpc/svc.h (__dispatch_fn_t): New. (svc_register): Use __dispatch_fn_t in prototype. 1997-05-28 17:02 Ulrich Drepper <drepper@cygnus.com> * sysdeps/generic/bzero.c (bzero): Fix typo. Patch by Witek Wnuk <spider@pest.waw.ids.edu.pl>. 1997-05-27 12:00 Andreas Jaeger <aj@arthur.rhein-neckar.de> * sysdeps/generic/vtimes.c: Use ISO C declaration style. * sysdeps/unix/bsd/ualarm.c: Include <unistd.h> for prototype. * sysdeps/generic/memccpy.c: Include <string.h> for prototype. * signal/tst-signal.c (handler): Correct function declaration to avoid warning. * stdlib/testsort.c (compare): Likewise. * string/tester.c: Likewise. 1997-05-27 14:16 Miles Bader <miles@gnu.ai.mit.edu> * argp-help.c (argp_args_usage): Supply correct argp to filter_doc. 1997-05-27 17:51 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * db/hash/extern.h, db/hash/hash.c, db/hash/hash.h, db/hash/hash_log2.c: Rename __log2 to __hash_log2 to avoid clash with libm. 1997-05-27 14:47 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/m68k/fpu/e_atan2.c: Fix missing negate. Use __m81_test instead of explicit comparisons. 1997-05-26 18:36 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * inet/netinet/icmp6.h: Remove use of <asm/bitops.h> which has no place in a generic header and is no user include file.
This commit is contained in:
parent
06bdbaa0a6
commit
76b87c039b
165
ChangeLog
165
ChangeLog
@ -1,3 +1,168 @@
|
||||
1997-05-29 12:48 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* io/ftw.c: Complete rewrite. Add implementation of `nftw'.
|
||||
* io/ftw.h: Update for new implementation and XPG4.2.
|
||||
|
||||
* login/Makefile: Update for UTMP daemon implementation.
|
||||
|
||||
Update resolver code to bind-4.9.6-T1A.
|
||||
* resolv/Banner: Update.
|
||||
* nss/digits_dots.c: Adapt text address matching to T1A.
|
||||
* nss/nss_files/files-hosts.c: Always use inet_pton.
|
||||
* resolv/base64.c (b64_pton): Follow T1A but don't use this code since
|
||||
it would lead to warnings.
|
||||
* resolv/gethnamaddr.c (getanswer): Test host name for maximal length
|
||||
at several places.
|
||||
* resolv/inet_net_pton.c (inet_net_pton_ipv4): Correct typo in comment.
|
||||
* resolv/res_comp.c (dn_expand): Check for overflow.
|
||||
(dn_comp): Likewise.
|
||||
* resolv/res_debug.c (precsize_aton): Better implementation.
|
||||
* resolv/res_init.c (res_init): Make `buf' of size MAXDNAME.
|
||||
* resolv/res_send.c (res_send): Check for overflow in descriptor set.
|
||||
* resolv/nss_dns/dns-host.c (getanswer_r): Test host name for maximal
|
||||
length at several places.
|
||||
|
||||
1997-05-29 12:51 Mark Kettenis <kettenis@phys.uva.nl>
|
||||
|
||||
* login/utmp-private.h (struct utfuncs): Add one more parameter
|
||||
to updwtmp function.
|
||||
Declare all three function jump tables.
|
||||
* login/utmp.h: Declare __utmpname.
|
||||
* login/getutent_r.c: Remove db backend and provide support for
|
||||
utmpd backend.
|
||||
* login/login.c: Use `updwtmp' function insteead of writing the
|
||||
record ourself.
|
||||
* login/logwtmp.c: Move `updwtmp' function to...
|
||||
* login/updwtmp.c: ...here. New file.
|
||||
* login/utmp_db.h: Removed.
|
||||
* login/utmp_file.c: Add updwtmp function to write to file.
|
||||
* login/utmp_daemon.c: New file. Daemon backend.
|
||||
* login/utmpname.c: New file. Implementation of utmpname function.
|
||||
* login/utmpdump.c: New file. Tool to dump utmp-like files.
|
||||
* login/utmpd/connection.c: New file.
|
||||
* login/utmpd/database.c: New file.
|
||||
* login/utmpd/error.c: New file.
|
||||
* login/utmpd/request.c: New file.
|
||||
* login/utmpd/utmpd-private.h: New file.
|
||||
* login/utmpd/utmpd.c: New file.
|
||||
* login/utmpd/utmpd.h: New file.
|
||||
* login/utmpd/xtmp.c: New file.
|
||||
* login/utmpd/xtmp.h: New file.
|
||||
|
||||
1997-05-29 12:28 Jim Meyering <meyering@eng.ascend.com>
|
||||
|
||||
* time/strftime.c: Correct/normalize indentation in cpp directives.
|
||||
|
||||
1997-05-28 20:43 Philip Blundell <pjb27@cam.ac.uk>
|
||||
|
||||
* nis/nis_error.c: Include <string.h> to fix warning.
|
||||
* nis/nis_print.c: Likewise.
|
||||
* nis/nss_nisplus/nisplus-hosts.c: Arg 3 of map_v4v6_hostent
|
||||
is int* not size_t*.
|
||||
|
||||
1997-05-28 21:56 Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
||||
|
||||
* math/cmathcalls.h: Correct typo in comment.
|
||||
|
||||
* inet/netinet/icmp6.h: Include <netinet/in.h> for in6_addr.
|
||||
|
||||
* sysdeps/unix/sysv/linux/netinet/ip_fw.h: Include <net/if.h> for
|
||||
IFNAMSIZ.
|
||||
|
||||
* sysdeps/unix/sysv/linux/net/ppp_defs.h: Include <time.h> for
|
||||
time_t.
|
||||
|
||||
* login/pty.h: Include <ioctl-types.h> for definition of struct
|
||||
winsize.
|
||||
|
||||
* misc/regexp.h (compile): Correct typo.
|
||||
|
||||
* argp/argp.h: Put extern before __const in defintion of
|
||||
argp_program_bug_address.
|
||||
|
||||
1997-05-29 00:20 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/wordsize-32/inttypes.h: Correct names of unsigned fast
|
||||
and least types. Correct names of ?INT_FAST*_{MIN,MAX} macros.
|
||||
* sysdeps/wordsize-64/inttypes.h: Likewise.
|
||||
Reported by Andreas Jaeger <aj@arthur.rhein-neckar.de>.
|
||||
|
||||
1997-05-28 22:51 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/unix/Makefile (make-ioctls-CFLAGS): Use generic
|
||||
ttydefaults.h file instead of non-existing version in termios/sys.
|
||||
Reported by Zack Weinberg <zack@rabi.phys.columbia.edu>.
|
||||
|
||||
* time/strptime.c (strptime_internal, case 'Y'): Restrict year
|
||||
number to four digits and to representable range for 4 byte time_t
|
||||
values.
|
||||
Patch by H.J. Lu <hjl@lucon.org>.
|
||||
|
||||
1997-05-28 18:19 Philip Blundell <pjb27@cam.ac.uk>
|
||||
|
||||
* posix/execl.c: Include <alloca.h> to avoid warning.
|
||||
|
||||
1997-05-27 18:19 Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
||||
|
||||
* math/libm-test.c: Implement testing of inlined functions, make
|
||||
output nicer, update comments.
|
||||
|
||||
* math/test-idouble.c: New file. Frontend for double tests of
|
||||
inlined functions.
|
||||
* math/test-ildoubl.c: New file. Frontend for long double tests of
|
||||
inlined functions.
|
||||
* math/test-ifloat.c: New file. Frontend for float tests of
|
||||
inlined functions.
|
||||
|
||||
* math/test-longdouble.c: Rename to...
|
||||
* math/test-ldouble.c: ...this.
|
||||
|
||||
* math/Makefile: Add rules for new test programs, change rules for
|
||||
renaming of longdouble test.
|
||||
|
||||
1997-05-20 15:50 H.J. Lu <hjl@gnu.ai.mit.edu>
|
||||
|
||||
* sunrpc/rpc/svc.h (__dispatch_fn_t): New.
|
||||
(svc_register): Use __dispatch_fn_t in prototype.
|
||||
|
||||
1997-05-28 17:02 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/generic/bzero.c (bzero): Fix typo.
|
||||
Patch by Witek Wnuk <spider@pest.waw.ids.edu.pl>.
|
||||
|
||||
1997-05-27 12:00 Andreas Jaeger <aj@arthur.rhein-neckar.de>
|
||||
|
||||
* sysdeps/generic/vtimes.c: Use ISO C declaration style.
|
||||
|
||||
* sysdeps/unix/bsd/ualarm.c: Include <unistd.h> for prototype.
|
||||
|
||||
* sysdeps/generic/memccpy.c: Include <string.h> for prototype.
|
||||
|
||||
* signal/tst-signal.c (handler): Correct function declaration to
|
||||
avoid warning.
|
||||
* stdlib/testsort.c (compare): Likewise.
|
||||
* string/tester.c: Likewise.
|
||||
|
||||
1997-05-27 14:16 Miles Bader <miles@gnu.ai.mit.edu>
|
||||
|
||||
* argp-help.c (argp_args_usage): Supply correct argp to filter_doc.
|
||||
|
||||
1997-05-27 17:51 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
|
||||
|
||||
* db/hash/extern.h, db/hash/hash.c, db/hash/hash.h,
|
||||
db/hash/hash_log2.c: Rename __log2 to __hash_log2 to avoid clash
|
||||
with libm.
|
||||
|
||||
1997-05-27 14:47 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
|
||||
|
||||
* sysdeps/m68k/fpu/e_atan2.c: Fix missing negate. Use __m81_test
|
||||
instead of explicit comparisons.
|
||||
|
||||
1997-05-26 18:36 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
|
||||
|
||||
* inet/netinet/icmp6.h: Remove use of <asm/bitops.h> which has no
|
||||
place in a generic header and is no user include file.
|
||||
|
||||
1997-05-27 02:20 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* stdio/obstream.c (obstack_printf): Fix bug in
|
||||
|
2
FAQ
2
FAQ
@ -432,7 +432,7 @@ ship the cryptographic function together with the libc.
|
||||
But of course we provide the code and there is an very easy way to use
|
||||
this code. First get the extra package. People in the US way get it
|
||||
from the same place they got the GNU libc from. People outside the US
|
||||
should get the code from ftp.uni-c.dk [129.142.6.74], or another
|
||||
should get the code from ftp://ftp.ifi.uio.no/pub/gnu, or another
|
||||
archive site outside the USA. The README explains how to install the
|
||||
sources.
|
||||
|
||||
|
@ -1315,8 +1315,7 @@ argp_args_usage (const struct argp *argp, const struct argp_state *state,
|
||||
int multiple = 0;
|
||||
const struct argp_child *child = argp->children;
|
||||
const char *tdoc = gettext (argp->args_doc), *nl = 0;
|
||||
const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC,
|
||||
state ? state->root_argp : 0, state);
|
||||
const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state);
|
||||
|
||||
if (fdoc)
|
||||
{
|
||||
|
@ -396,7 +396,7 @@ extern void (*argp_program_version_hook) __P ((FILE *__stream,
|
||||
argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various
|
||||
standard help messages), embedded in a sentence that says something like
|
||||
`Report bugs to ADDR.'. */
|
||||
__const extern char *argp_program_bug_address;
|
||||
extern __const char *argp_program_bug_address;
|
||||
|
||||
/* The exit status that argp will use when exiting due to a parsing error.
|
||||
If not defined or set by the user program, this defaults to EX_USAGE from
|
||||
|
@ -52,7 +52,7 @@ void __free_ovflpage __P((HTAB *, BUFHEAD *));
|
||||
BUFHEAD *__get_buf __P((HTAB *, u_int32_t, BUFHEAD *, int));
|
||||
int __get_page __P((HTAB *, char *, u_int32_t, int, int, int));
|
||||
int __ibitmap __P((HTAB *, int, int, int));
|
||||
u_int32_t __log2 __P((u_int32_t));
|
||||
u_int32_t __hash_log2 __P((u_int32_t));
|
||||
int __put_page __P((HTAB *, char *, u_int32_t, int, int));
|
||||
void __reclaim_buf __P((HTAB *, BUFHEAD *));
|
||||
int __split_page __P((HTAB *, u_int32_t, u_int32_t));
|
||||
|
@ -303,13 +303,13 @@ init_hash(hashp, file, info)
|
||||
if (stat(file, &statbuf))
|
||||
return (NULL);
|
||||
hashp->BSIZE = statbuf.st_blksize;
|
||||
hashp->BSHIFT = __log2(hashp->BSIZE);
|
||||
hashp->BSHIFT = __hash_log2(hashp->BSIZE);
|
||||
}
|
||||
|
||||
if (info) {
|
||||
if (info->bsize) {
|
||||
/* Round pagesize up to power of 2 */
|
||||
hashp->BSHIFT = __log2(info->bsize);
|
||||
hashp->BSHIFT = __hash_log2(info->bsize);
|
||||
hashp->BSIZE = 1 << hashp->BSHIFT;
|
||||
if (hashp->BSIZE > MAX_BSIZE) {
|
||||
errno = EINVAL;
|
||||
@ -358,7 +358,7 @@ init_htab(hashp, nelem)
|
||||
*/
|
||||
nelem = (nelem - 1) / hashp->FFACTOR + 1;
|
||||
|
||||
l2 = __log2(MAX(nelem, 2));
|
||||
l2 = __hash_log2(MAX(nelem, 2));
|
||||
nbuckets = 1 << l2;
|
||||
|
||||
hashp->SPARES[l2] = l2 + 1;
|
||||
@ -376,7 +376,7 @@ init_htab(hashp, nelem)
|
||||
hashp->BSHIFT) + 1;
|
||||
|
||||
nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
|
||||
nsegs = 1 << __log2(nsegs);
|
||||
nsegs = 1 << __hash_log2(nsegs);
|
||||
|
||||
if (nsegs > hashp->DSIZE)
|
||||
hashp->DSIZE = nsegs;
|
||||
@ -843,7 +843,7 @@ __expand_table(hashp)
|
||||
* * increases), we need to copy the current contents of the spare
|
||||
* split bucket to the next bucket.
|
||||
*/
|
||||
spare_ndx = __log2(hashp->MAX_BUCKET + 1);
|
||||
spare_ndx = __hash_log2(hashp->MAX_BUCKET + 1);
|
||||
if (spare_ndx > hashp->OVFL_POINT) {
|
||||
hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
|
||||
hashp->OVFL_POINT = spare_ndx;
|
||||
|
@ -170,7 +170,7 @@ typedef struct htab { /* Memory resident data structure */
|
||||
#define OADDR_OF(S,O) ((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
|
||||
|
||||
#define BUCKET_TO_PAGE(B) \
|
||||
(B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__log2((B)+1)-1] : 0)
|
||||
(B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__hash_log2((B)+1)-1] : 0)
|
||||
#define OADDR_TO_PAGE(B) \
|
||||
BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
|
||||
|
||||
|
@ -42,10 +42,10 @@ static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94";
|
||||
|
||||
#include <db.h>
|
||||
|
||||
u_int32_t __log2 __P((u_int32_t));
|
||||
u_int32_t __hash_log2 __P((u_int32_t));
|
||||
|
||||
u_int32_t
|
||||
__log2(num)
|
||||
__hash_log2(num)
|
||||
u_int32_t num;
|
||||
{
|
||||
register u_int32_t i, limit;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define _NETINET_ICMP6_H 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define ICMPV6_FILTER 1
|
||||
|
||||
@ -77,21 +78,6 @@ struct icmpv6hdr
|
||||
#define ICMPV6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */
|
||||
#define ICMPV6_PARAMPROB_OPTION 2 /* unrecognized option */
|
||||
|
||||
#if defined(__OPTIMIZE__)
|
||||
#include <asm/bitops.h>
|
||||
|
||||
#define ICMPV6_FILTER_WILLPASS(type, filterp) \
|
||||
(test_bit (type, filterp) == 0)
|
||||
|
||||
#define ICMPV6_FILTER_WILLBLOCK(type, filterp) \
|
||||
test_bit (type, filterp)
|
||||
|
||||
#define ICMPV6_FILTER_SETPASS(type, filterp) \
|
||||
clear_bit (type & 0x1f, &((filterp)->data[type >> 5]))
|
||||
|
||||
#define ICMPV6_FILTER_SETBLOCK(type, filterp) \
|
||||
set_bit (type & 0x1f, &((filterp)->data[type >> 5]))
|
||||
#else
|
||||
#define ICMPV6_FILTER_WILLPASS(type, filterp) \
|
||||
((((filterp)->data[(type) >> 5]) & (1 << ((type) & 31))) == 0)
|
||||
|
||||
@ -103,7 +89,6 @@ struct icmpv6hdr
|
||||
|
||||
#define ICMPV6_FILTER_SETBLOCK(type, filterp) \
|
||||
((((filterp)->data[(type) >> 5]) |= (1 << ((type) & 31))))
|
||||
#endif
|
||||
|
||||
#define ICMPV6_FILTER_SETPASSALL(filterp) \
|
||||
memset (filterp, 0, sizeof (struct icmpv6_filter));
|
||||
|
621
io/ftw.c
621
io/ftw.c
@ -1,6 +1,7 @@
|
||||
/* Copyright (C) 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
/* File tree walker functions.
|
||||
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ian Lance Taylor (ian@airs.com).
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
@ -17,197 +18,507 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <ftw.h>
|
||||
#include <search.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ftw.h>
|
||||
|
||||
/* #define NDEBUG 1 */
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024 /* XXX */
|
||||
#endif
|
||||
|
||||
|
||||
/* Traverse one level of a directory tree. */
|
||||
|
||||
static int
|
||||
ftw_dir (DIR **dirs, int level, int descriptors, char *dir, size_t len,
|
||||
int (*func) (const char *file, const struct stat *status, int flag))
|
||||
struct dir_data
|
||||
{
|
||||
int got;
|
||||
struct dirent *entry;
|
||||
DIR *stream;
|
||||
char *content;
|
||||
};
|
||||
|
||||
got = 0;
|
||||
struct ftw_data
|
||||
{
|
||||
struct dir_data **dirstreams;
|
||||
size_t actdir;
|
||||
size_t maxdir;
|
||||
|
||||
__set_errno (0);
|
||||
char *dirbuf;
|
||||
size_t dirbufsize;
|
||||
struct FTW ftw;
|
||||
|
||||
while ((entry = readdir (dirs[level])) != NULL)
|
||||
int flags;
|
||||
|
||||
int *cvt_arr;
|
||||
__nftw_func_t func;
|
||||
|
||||
struct stat st;
|
||||
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
|
||||
/* Internally we use the FTW_* constants used for `nftw'. When the
|
||||
process called `ftw' we must reduce the flag to the known flags
|
||||
for `ftw'. */
|
||||
static int nftw_arr[] =
|
||||
{
|
||||
FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
|
||||
};
|
||||
|
||||
static int ftw_arr[] =
|
||||
{
|
||||
FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
|
||||
};
|
||||
|
||||
|
||||
/* Forward declarations of local functions. */
|
||||
static int ftw_dir (struct ftw_data *data);
|
||||
|
||||
|
||||
static inline int
|
||||
open_dir_stream (struct ftw_data *data, struct dir_data *dirp)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (data->dirstreams[data->actdir] != NULL)
|
||||
{
|
||||
struct stat s;
|
||||
int flag, retval, newlev;
|
||||
size_t namlen;
|
||||
/* Oh, oh. We must close this stream. Get all remaining
|
||||
entries and store them as a list in the `content' member of
|
||||
the `struct dir_data' variable. */
|
||||
size_t bufsize = 1024;
|
||||
char *buf = malloc (bufsize);
|
||||
|
||||
++got;
|
||||
|
||||
if (entry->d_name[0] == '.'
|
||||
&& (entry->d_name[1] == '\0' ||
|
||||
(entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
|
||||
if (buf == NULL)
|
||||
result = -1;
|
||||
else
|
||||
{
|
||||
__set_errno (0);
|
||||
continue;
|
||||
}
|
||||
DIR *st = data->dirstreams[data->actdir]->stream;
|
||||
struct dirent *d;
|
||||
size_t actsize = 0;
|
||||
|
||||
namlen = _D_EXACT_NAMLEN (entry);
|
||||
while ((d = readdir (st)) != NULL)
|
||||
{
|
||||
size_t this_len = _D_EXACT_NAMLEN (d);
|
||||
if (actsize + this_len + 2 >= bufsize)
|
||||
{
|
||||
char *newp;
|
||||
bufsize += MAX (1024, 2 * this_len);
|
||||
newp = realloc (buf, bufsize);
|
||||
if (newp == NULL)
|
||||
{
|
||||
/* No more memory. */
|
||||
int save_err = errno;
|
||||
free (buf);
|
||||
__set_errno (save_err);
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
buf = newp;
|
||||
}
|
||||
|
||||
if (namlen + len + 1 > PATH_MAX)
|
||||
{
|
||||
#ifdef ENAMETOOLONG
|
||||
__set_errno (ENAMETOOLONG);
|
||||
#else
|
||||
__set_errno (ENOMEM);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
memcpy (buf + actsize, d->d_name, this_len);
|
||||
actsize += this_len;
|
||||
buf[actsize++] = '\0';
|
||||
}
|
||||
|
||||
dir[len] = '/';
|
||||
memcpy ((void *) (dir + len + 1), (void *) entry->d_name,
|
||||
namlen + 1);
|
||||
/* Terminate the list with an additional NUL byte. */
|
||||
buf[actsize++] = '\0';
|
||||
|
||||
if (stat (dir, &s) < 0)
|
||||
{
|
||||
if (errno != EACCES && errno != ENOENT)
|
||||
return -1;
|
||||
flag = FTW_NS;
|
||||
}
|
||||
else if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
newlev = (level + 1) % descriptors;
|
||||
|
||||
if (dirs[newlev] != NULL)
|
||||
closedir (dirs[newlev]);
|
||||
|
||||
dirs[newlev] = opendir (dir);
|
||||
if (dirs[newlev] != NULL)
|
||||
flag = FTW_D;
|
||||
/* Shrink the buffer to what we actually need. */
|
||||
data->dirstreams[data->actdir]->content = realloc (buf, actsize);
|
||||
if (data->dirstreams[data->actdir]->content == NULL)
|
||||
{
|
||||
int save_err = errno;
|
||||
free (buf);
|
||||
__set_errno (save_err);
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != EACCES)
|
||||
return -1;
|
||||
flag = FTW_DNR;
|
||||
closedir (st);
|
||||
data->dirstreams[data->actdir]->stream = NULL;
|
||||
data->dirstreams[data->actdir] = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
flag = FTW_F;
|
||||
|
||||
retval = (*func) (dir, &s, flag);
|
||||
|
||||
if (flag == FTW_D)
|
||||
{
|
||||
if (retval == 0)
|
||||
retval = ftw_dir (dirs, newlev, descriptors, dir,
|
||||
namlen + len + 1, func);
|
||||
if (dirs[newlev] != NULL)
|
||||
{
|
||||
int save;
|
||||
|
||||
save = errno;
|
||||
closedir (dirs[newlev]);
|
||||
__set_errno (save);
|
||||
dirs[newlev] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
|
||||
if (dirs[level] == NULL)
|
||||
{
|
||||
int skip;
|
||||
|
||||
dir[len] = '\0';
|
||||
dirs[level] = opendir (dir);
|
||||
if (dirs[level] == NULL)
|
||||
return -1;
|
||||
skip = got;
|
||||
while (skip-- != 0)
|
||||
{
|
||||
__set_errno (0);
|
||||
if (readdir (dirs[level]) == NULL)
|
||||
return errno == 0 ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
__set_errno (0);
|
||||
}
|
||||
|
||||
return errno == 0 ? 0 : -1;
|
||||
/* Open the new stream. */
|
||||
if (result == 0)
|
||||
{
|
||||
assert (data->dirstreams[data->actdir] == NULL);
|
||||
|
||||
dirp->stream = opendir (data->dirbuf);
|
||||
if (dirp->stream == NULL)
|
||||
result = -1;
|
||||
else
|
||||
{
|
||||
dirp->content = NULL;
|
||||
data->dirstreams[data->actdir] = dirp;
|
||||
|
||||
if (++data->actdir == data->maxdir)
|
||||
data->actdir = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Call a function on every element in a directory tree. */
|
||||
|
||||
int
|
||||
ftw (const char *dir,
|
||||
int (*func) (const char *file, const struct stat *status, int flag),
|
||||
int descriptors)
|
||||
static inline int
|
||||
process_entry (struct ftw_data *data, struct dir_data *dir, const char *name,
|
||||
size_t namlen)
|
||||
{
|
||||
DIR **dirs;
|
||||
size_t len;
|
||||
char buf[PATH_MAX + 1];
|
||||
struct stat s;
|
||||
int flag, retval;
|
||||
int i;
|
||||
int result = 0;
|
||||
int flag;
|
||||
|
||||
if (descriptors <= 0)
|
||||
descriptors = 1;
|
||||
if (name[0] == '.' && (name[1] == '\0'
|
||||
|| (name[1] == '.' && name[2] == '\0')))
|
||||
/* Don't process the "." and ".." entries. */
|
||||
return 0;
|
||||
|
||||
dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
|
||||
i = descriptors;
|
||||
while (i-- > 0)
|
||||
dirs[i] = NULL;
|
||||
if (data->dirbufsize < data->ftw.base + namlen + 2)
|
||||
{
|
||||
/* Enlarge the buffer. */
|
||||
char *newp;
|
||||
|
||||
if (stat (dir, &s) < 0)
|
||||
data->dirbufsize *= 2;
|
||||
newp = realloc (data->dirbuf, data->dirbufsize);
|
||||
if (newp == NULL)
|
||||
return -1;
|
||||
data->dirbuf = newp;
|
||||
}
|
||||
|
||||
memcpy (data->dirbuf + data->ftw.base, name, namlen);
|
||||
data->dirbuf[data->ftw.base + namlen] = '\0';
|
||||
|
||||
if (((data->flags & FTW_PHYS) ? lstat : stat) (data->dirbuf, &data->st) < 0)
|
||||
{
|
||||
if (errno != EACCES && errno != ENOENT)
|
||||
return -1;
|
||||
flag = FTW_NS;
|
||||
}
|
||||
else if (S_ISDIR (s.st_mode))
|
||||
{
|
||||
dirs[0] = opendir (dir);
|
||||
if (dirs[0] != NULL)
|
||||
flag = FTW_D;
|
||||
result = -1;
|
||||
else if (!(data->flags & FTW_PHYS)
|
||||
&& lstat (data->dirbuf, &data->st) == 0
|
||||
&& S_ISLNK (data->st.st_mode))
|
||||
flag = FTW_SLN;
|
||||
else
|
||||
{
|
||||
if (errno != EACCES)
|
||||
return -1;
|
||||
flag = FTW_DNR;
|
||||
}
|
||||
flag = FTW_NS;
|
||||
}
|
||||
else
|
||||
flag = FTW_F;
|
||||
|
||||
len = strlen (dir);
|
||||
memcpy ((void *) buf, (void *) dir, len + 1);
|
||||
|
||||
retval = (*func) (buf, &s, flag);
|
||||
|
||||
if (flag == FTW_D)
|
||||
{
|
||||
if (retval == 0)
|
||||
retval = ftw_dir (dirs, 0, descriptors, buf, len, func);
|
||||
if (dirs[0] != NULL)
|
||||
{
|
||||
int save;
|
||||
if (S_ISDIR (data->st.st_mode))
|
||||
flag = FTW_D;
|
||||
else if (S_ISLNK (data->st.st_mode))
|
||||
flag = FTW_SL;
|
||||
else
|
||||
flag = FTW_F;
|
||||
}
|
||||
|
||||
save = errno;
|
||||
closedir (dirs[0]);
|
||||
__set_errno (save);
|
||||
if (result == 0
|
||||
&& (!(data->flags & FTW_MOUNT) || data->st.st_dev == data->dev))
|
||||
{
|
||||
if (flag == FTW_D)
|
||||
{
|
||||
result = ftw_dir (data);
|
||||
|
||||
if (result == 0 && (data->flags & FTW_CHDIR))
|
||||
{
|
||||
/* Change back to current directory. */
|
||||
int done = 0;
|
||||
if (dir->stream != NULL)
|
||||
if (fchdir (dirfd (dir->stream)) == 0)
|
||||
done = 1;
|
||||
|
||||
if (!done)
|
||||
{
|
||||
if (data->ftw.base == 1)
|
||||
{
|
||||
if (chdir ("/") < 0)
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Please note that we overwrite a slash. */
|
||||
data->dirbuf[data->ftw.base - 1] = '\0';
|
||||
|
||||
if (chdir (data->dirbuf) < 0)
|
||||
result = -1;
|
||||
else
|
||||
data->dirbuf[data->ftw.base - 1] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
result = (*data->func) (data->dirbuf, &data->st, data->cvt_arr[flag],
|
||||
&data->ftw);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ftw_dir (struct ftw_data *data)
|
||||
{
|
||||
struct dir_data dir;
|
||||
struct dirent *d;
|
||||
int previous_base = data->ftw.base;
|
||||
int result = 0;
|
||||
char *startp;
|
||||
|
||||
/* First, report the directory (if not depth-first). */
|
||||
if (!(data->flags & FTW_DEPTH))
|
||||
{
|
||||
result = (*data->func) (data->dirbuf, &data->st, FTW_D, &data->ftw);
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Open the stream for this directory. This might require that
|
||||
another stream has to be closed. */
|
||||
result = open_dir_stream (data, &dir);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
/* If necessary, change to this directory. */
|
||||
if (data->flags & FTW_CHDIR)
|
||||
{
|
||||
if (fchdir (dirfd (dir.stream)) < 0)
|
||||
{
|
||||
if (errno == ENOSYS)
|
||||
{
|
||||
if (chdir (data->dirbuf) < 0)
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
result = -1;
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
int save_err = errno;
|
||||
closedir (dir.stream);
|
||||
__set_errno (save_err);
|
||||
|
||||
if (data->actdir-- == 0)
|
||||
data->actdir = data->maxdir - 1;
|
||||
data->dirstreams[data->actdir] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
/* Next, update the `struct FTW' information. */
|
||||
++data->ftw.level;
|
||||
startp = strchr (data->dirbuf, '\0');
|
||||
*startp++ = '/';
|
||||
data->ftw.base = startp - data->dirbuf;
|
||||
|
||||
while (dir.stream != NULL && (d = readdir (dir.stream)) != NULL)
|
||||
{
|
||||
result = process_entry (data, &dir, d->d_name, _D_EXACT_NAMLEN (d));
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir.stream != NULL)
|
||||
{
|
||||
/* The stream is still open. I.e., we did not need more
|
||||
descriptors. Simply close the stream now. */
|
||||
int save_err = errno;
|
||||
|
||||
assert (dir.content == NULL);
|
||||
|
||||
closedir (dir.stream);
|
||||
__set_errno (save_err);
|
||||
|
||||
if (data->actdir-- == 0)
|
||||
data->actdir = data->maxdir - 1;
|
||||
data->dirstreams[data->actdir] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int save_err;
|
||||
char *runp = dir.content;
|
||||
|
||||
assert (result == 0);
|
||||
|
||||
while (*runp != '\0')
|
||||
{
|
||||
char *endp = strchr (runp, '\0');
|
||||
|
||||
result = process_entry (data, &dir, runp, endp - runp);
|
||||
if (result != 0)
|
||||
break;
|
||||
|
||||
runp = endp + 1;
|
||||
}
|
||||
|
||||
save_err = errno;
|
||||
free (dir.content);
|
||||
__set_errno (save_err);
|
||||
}
|
||||
|
||||
/* Prepare the return, revert the `struct FTW' information. */
|
||||
--data->ftw.level;
|
||||
data->ftw.base = previous_base;
|
||||
|
||||
/* Finally, if we process depth-first report the directory. */
|
||||
if (result == 0 && (data->flags & FTW_DEPTH))
|
||||
result = (*data->func) (data->dirbuf, &data->st, FTW_DP, &data->ftw);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
|
||||
int flags)
|
||||
{
|
||||
struct ftw_data data;
|
||||
int result = 0;
|
||||
int save_err;
|
||||
char *cwd;
|
||||
char *cp;
|
||||
|
||||
/* First make sure the parameters are reasonable. */
|
||||
if (dir[0] == '\0')
|
||||
{
|
||||
__set_errno (ENOTDIR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.maxdir = descriptors < 1 ? 1 : descriptors;
|
||||
data.actdir = 0;
|
||||
data.dirstreams = (struct dir_data **) alloca (data.maxdir
|
||||
* sizeof (struct dir_data *));
|
||||
memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
|
||||
|
||||
data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
|
||||
data.dirbuf = (char *) malloc (data.dirbufsize);
|
||||
if (data.dirbuf == NULL)
|
||||
return -1;
|
||||
cp = stpcpy (data.dirbuf, dir);
|
||||
/* Strip trailing slashes. */
|
||||
while (cp > data.dirbuf + 1 && cp[-1] == '/')
|
||||
--cp;
|
||||
*cp = '\0';
|
||||
|
||||
data.ftw.level = 0;
|
||||
|
||||
/* Find basename. */
|
||||
while (cp > data.dirbuf && cp[-1] != '/')
|
||||
--cp;
|
||||
data.ftw.base = cp - data.dirbuf;
|
||||
|
||||
data.flags = flags;
|
||||
|
||||
/* This assignment might seem to be strange but it is what we want.
|
||||
The trick is that the first three arguments to the `ftw' and
|
||||
`nftw' callback functions are equal. Therefore we can call in
|
||||
every case the callback using the format of the `nftw' version
|
||||
and get the correct result since the stack layout for a function
|
||||
call in C allows this. */
|
||||
data.func = (__nftw_func_t) func;
|
||||
|
||||
/* Since we internally use the complete set of FTW_* values we need
|
||||
to reduce the value range before calling a `ftw' callback. */
|
||||
data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
|
||||
|
||||
/* Now go to the directory containing the initial file/directory. */
|
||||
if ((flags & FTW_CHDIR) && data.ftw.base > 0)
|
||||
{
|
||||
/* GNU extension ahead. */
|
||||
cwd = getcwd (NULL, 0);
|
||||
if (cwd == NULL)
|
||||
result = -1;
|
||||
else
|
||||
{
|
||||
/* Change to the directory the file is in. In data.dirbuf
|
||||
we have a writable copy of the file name. Just NUL
|
||||
terminate it for now and change the directory. */
|
||||
if (data.ftw.base == 1)
|
||||
/* I.e., the file is in the root directory. */
|
||||
result = chdir ("/");
|
||||
else
|
||||
{
|
||||
char ch = data.dirbuf[data.ftw.base - 1];
|
||||
data.dirbuf[data.ftw.base - 1] = '\0';
|
||||
result = chdir (data.dirbuf);
|
||||
data.dirbuf[data.ftw.base - 1] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get stat info for start directory. */
|
||||
if (result == 0)
|
||||
if (((flags & FTW_PHYS) ? lstat : stat) (data.dirbuf, &data.st) < 0)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
result = (*data.func) (data.dirbuf, &data.st, FTW_NS, &data.ftw);
|
||||
else if (!(flags & FTW_PHYS)
|
||||
&& errno == ENOENT
|
||||
&& lstat (dir, &data.st) == 0 && S_ISLNK (data.st.st_mode))
|
||||
result = (*data.func) (data.dirbuf, &data.st, data.cvt_arr[FTW_SLN],
|
||||
&data.ftw);
|
||||
else
|
||||
/* No need to call the callback since we cannot say anything
|
||||
about the object. */
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (S_ISDIR (data.st.st_mode))
|
||||
{
|
||||
data.dev = data.st.st_dev;
|
||||
result = ftw_dir (&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
int flag = S_ISLNK (data.st.st_mode) ? FTW_SL : FTW_F;
|
||||
|
||||
result = (*data.func) (data.dirbuf, &data.st, data.cvt_arr[flag],
|
||||
&data.ftw);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return to the start directory (if necessary). */
|
||||
if (cwd != NULL)
|
||||
{
|
||||
int save_err = errno;
|
||||
chdir (cwd);
|
||||
free (cwd);
|
||||
__set_errno (save_err);
|
||||
}
|
||||
|
||||
/* Free all memory. */
|
||||
save_err = errno;
|
||||
free (data.dirbuf);
|
||||
__set_errno (save_err);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Entry points. */
|
||||
|
||||
int
|
||||
ftw (path, func, descriptors)
|
||||
const char *path;
|
||||
__ftw_func_t func;
|
||||
int descriptors;
|
||||
{
|
||||
return ftw_startup (path, 0, func, descriptors, 0);
|
||||
}
|
||||
|
||||
int
|
||||
nftw (path, func, descriptors, flags)
|
||||
const char *path;
|
||||
__nftw_func_t func;
|
||||
int descriptors;
|
||||
int flags;
|
||||
{
|
||||
return ftw_startup (path, 1, func, descriptors, flags);
|
||||
}
|
||||
|
81
io/ftw.h
81
io/ftw.h
@ -1,6 +1,5 @@
|
||||
/* Copyright (C) 1992, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ian Lance Taylor (ian@airs.com).
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
@ -26,22 +25,82 @@
|
||||
#define _FTW_H 1
|
||||
#include <features.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <statbuf.h>
|
||||
|
||||
/* The FLAG argument to the user function passed to ftw. */
|
||||
#define FTW_F 0 /* Regular file. */
|
||||
#define FTW_D 1 /* Directory. */
|
||||
#define FTW_DNR 2 /* Unreadable directory. */
|
||||
#define FTW_NS 3 /* Unstatable file. */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* Values for the FLAG argument to the user function passed to `ftw'
|
||||
and 'nftw'. */
|
||||
enum
|
||||
{
|
||||
FTW_F, /* Regular file. */
|
||||
#define FTW_F FTW_F
|
||||
FTW_D, /* Directory. */
|
||||
#define FTW_D FTW_D
|
||||
FTW_DNR, /* Unreadable directory. */
|
||||
#define FTW_DNR FTW_DNR
|
||||
FTW_NS, /* Unstatable file. */
|
||||
#define FTW_NS FTW_NS
|
||||
|
||||
#ifdef __USE_XOPEN_EXTENDED
|
||||
|
||||
FTW_SL, /* Symbolic link. */
|
||||
# define FTW_SL FTW_SL
|
||||
|
||||
/* These flags are only passed from the `nftw' function. */
|
||||
FTW_DP, /* Directory, all subdirs have been visited. */
|
||||
# define FTW_DP FTW_DP
|
||||
FTW_SLN /* Symbolic link naming non-existing file. */
|
||||
# define FTW_SLN FTW_SLN
|
||||
|
||||
#endif /* extended X/Open */
|
||||
};
|
||||
|
||||
|
||||
#ifdef __USE_XOPEN_EXTENDED
|
||||
/* Flags for fourth argument of `nftw'. */
|
||||
enum
|
||||
{
|
||||
FTW_PHYS = 1, /* Perform physical walk, ignore symlinks. */
|
||||
# define FTW_PHYS FTW_PHYS
|
||||
FTW_MOUNT = 2, /* Report only files on same file system as the
|
||||
argument. */
|
||||
# define FTW_MOUNT FTW_MOUNT
|
||||
FTW_CHDIR = 4, /* Change to current directory while processing it. */
|
||||
# define FTW_CHDIR FTW_CHDIR
|
||||
FTW_DEPTH = 8 /* Report files in directory before directory itself.*/
|
||||
# define FTW_DEPTH FTW_DEPTH
|
||||
};
|
||||
|
||||
/* Structure used for fourth argument to callback function for `nftw'. */
|
||||
struct FTW
|
||||
{
|
||||
int base;
|
||||
int level;
|
||||
};
|
||||
#endif /* extended X/Open */
|
||||
|
||||
|
||||
/* Convenient types for callback functions. */
|
||||
typedef int (*__ftw_func_t) __P ((__const char *filename,
|
||||
__const struct stat *status, int flag));
|
||||
#ifdef __USE_XOPEN_EXTENDED
|
||||
typedef int (*__nftw_func_t) __P ((__const char *filename,
|
||||
__const struct stat *status, int flag,
|
||||
struct FTW *));
|
||||
#endif
|
||||
|
||||
/* Call a function on every element in a directory tree. */
|
||||
extern int ftw __P ((__const char *__dir,
|
||||
int (*__func) (__const char *__file,
|
||||
__const struct stat *__status,
|
||||
int __flag),
|
||||
int __descriptors));
|
||||
extern int ftw __P ((__const char *dir, __ftw_func_t func, int descriptors));
|
||||
|
||||
#ifdef __USE_XOPEN_EXTENDED
|
||||
/* Call a function on every element in a directory tree. FLAG allows
|
||||
to specify the behaviour more detailed. */
|
||||
extern int nftw __P ((__const char *dir, __nftw_func_t func,
|
||||
int descriptors, int flag));
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
@ -25,9 +25,15 @@ subdir := login
|
||||
headers := utmp.h utmpbits.h lastlog.h pty.h
|
||||
|
||||
routines := getutent getutent_r getutid getutline getutid_r getutline_r \
|
||||
utmp_file utmp_db
|
||||
utmp_file utmp_daemon utmpname
|
||||
|
||||
distribute := utmp-private.h
|
||||
others = utmpd
|
||||
install-sbin = utmpd
|
||||
utmpd-routines := connection database error request xtmp
|
||||
|
||||
distribute := utmp-private.h utmpd/xtmp.h utmpd/utmpd.h utmpd/utmpd-private.h
|
||||
|
||||
vpath %.c utmpd
|
||||
|
||||
# Build the -lutil library with these extra functions.
|
||||
extra-libs := libutil
|
||||
@ -37,6 +43,8 @@ libutil-routines:= login login_tty logout logwtmp pty
|
||||
|
||||
include ../Rules
|
||||
|
||||
$(objpfx)utmpd: $(utmpd-routines:%=$(objpfx)%.o)
|
||||
|
||||
# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
|
||||
# This ensures they will load libc.so for needed symbols if loaded by
|
||||
# a statically-linked program that hasn't already loaded it.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>
|
||||
and Paul Janzen <pcj@primenet.com>, 1996.
|
||||
@ -19,49 +19,48 @@
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <db.h>
|
||||
#include <fcntl.h>
|
||||
#if _LIBC
|
||||
#include <libc-lock.h>
|
||||
#include <limits.h>
|
||||
#else
|
||||
#define __libc_lock_lock(lock) ((void) 0)
|
||||
#define __libc_lock_unlock(lock) ((void) 0)
|
||||
#define __libc_lock_define_initialized(CLASS,NAME)
|
||||
#define weak_alias(name, aliasname) \
|
||||
extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
/* The various backends we have. */
|
||||
static int __setutent_unknown (int reset);
|
||||
static int __getutent_r_unknown (struct utmp *buffer, struct utmp **result);
|
||||
static struct utmp *__pututline_unknown (const struct utmp *data);
|
||||
static void __endutent_unknown (void);
|
||||
static int setutent_unknown (int reset);
|
||||
static int getutent_r_unknown (struct utmp *buffer, struct utmp **result);
|
||||
static struct utmp *pututline_unknown (const struct utmp *data);
|
||||
static void endutent_unknown (void);
|
||||
|
||||
|
||||
/* We have three jump tables: unknown, db, or file. */
|
||||
static struct utfuncs unknown_functions =
|
||||
/* Initial Jump table. */
|
||||
struct utfuncs __libc_utmp_unknown_functions =
|
||||
{
|
||||
__setutent_unknown,
|
||||
__getutent_r_unknown,
|
||||
setutent_unknown,
|
||||
getutent_r_unknown,
|
||||
NULL,
|
||||
NULL,
|
||||
__pututline_unknown,
|
||||
__endutent_unknown,
|
||||
pututline_unknown,
|
||||
endutent_unknown,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Currently selected backend. */
|
||||
struct utfuncs *__libc_utmp_jump_table = &unknown_functions;
|
||||
|
||||
/* The tables from the services. */
|
||||
extern struct utfuncs __libc_utmp_db_functions;
|
||||
extern struct utfuncs __libc_utmp_file_functions;
|
||||
|
||||
struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
|
||||
/* We need to protect the opening of the file. */
|
||||
__libc_lock_define_initialized (, __libc_utmp_lock)
|
||||
|
||||
|
||||
void
|
||||
__setutent (void)
|
||||
{
|
||||
@ -75,22 +74,31 @@ weak_alias (__setutent, setutent)
|
||||
|
||||
|
||||
static int
|
||||
__setutent_unknown (int reset)
|
||||
setutent_unknown (int reset)
|
||||
{
|
||||
/* We have to test whether it is still not decided which backend to use. */
|
||||
assert (__libc_utmp_jump_table == &unknown_functions);
|
||||
assert (__libc_utmp_jump_table == &__libc_utmp_unknown_functions);
|
||||
|
||||
/* See whether utmp db file exists. */
|
||||
if ((*__libc_utmp_db_functions.setutent) (reset))
|
||||
__libc_utmp_jump_table = &__libc_utmp_db_functions;
|
||||
/* See whether utmpd is running. */
|
||||
if ((*__libc_utmp_daemon_functions.setutent) (reset))
|
||||
__libc_utmp_jump_table = &__libc_utmp_daemon_functions;
|
||||
else
|
||||
{
|
||||
/* Either the db file does not exist or we have other
|
||||
problems. So use the normal file. */
|
||||
/* Use the normal file, but if the current file is _PATH_UTMP or
|
||||
_PATH_WTMP and the corresponding extended file (with an extra
|
||||
'x' added to the pathname) exists, we use the extended file,
|
||||
because the original file is in a different format. */
|
||||
if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0
|
||||
&& __access (_PATH_UTMP "x", F_OK) == 0)
|
||||
__utmpname (_PATH_UTMP "x");
|
||||
else if (strcmp (__libc_utmp_file_name, _PATH_WTMP) == 0
|
||||
&& __access (_PATH_WTMP "x", F_OK) == 0)
|
||||
__utmpname (_PATH_WTMP "x");
|
||||
|
||||
(*__libc_utmp_file_functions.setutent) (reset);
|
||||
__libc_utmp_jump_table = &__libc_utmp_file_functions;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -108,7 +116,7 @@ weak_alias (__endutent, endutent)
|
||||
|
||||
|
||||
static void
|
||||
__endutent_unknown (void)
|
||||
endutent_unknown (void)
|
||||
{
|
||||
/* Huh, how do we came here? Nothing to do. */
|
||||
}
|
||||
@ -131,10 +139,10 @@ weak_alias (__getutent_r, getutent_r)
|
||||
|
||||
|
||||
static int
|
||||
__getutent_r_unknown (struct utmp *buffer, struct utmp **result)
|
||||
getutent_r_unknown (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
/* It is not yet initialized. */
|
||||
__setutent_unknown (0);
|
||||
setutent_unknown (0);
|
||||
|
||||
return (*__libc_utmp_jump_table->getutent_r) (buffer, result);
|
||||
}
|
||||
@ -157,43 +165,10 @@ weak_alias (__pututline, pututline)
|
||||
|
||||
|
||||
static struct utmp *
|
||||
__pututline_unknown (const struct utmp *data)
|
||||
pututline_unknown (const struct utmp *data)
|
||||
{
|
||||
/* It is not yet initialized. */
|
||||
__setutent_unknown (0);
|
||||
setutent_unknown (0);
|
||||
|
||||
return (*__libc_utmp_jump_table->pututline) (data);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
__utmpname (const char *file)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
/* Close the old file. */
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
|
||||
/* Store new names. */
|
||||
if ((*__libc_utmp_file_functions.utmpname) (file) == 0
|
||||
&& !(*__libc_utmp_db_functions.utmpname) (file) == 0)
|
||||
{
|
||||
/* Try to find out whether we are supposed to work with a db
|
||||
file or not. Do this by looking for the extension ".db". */
|
||||
const char *ext = strrchr (file, '.');
|
||||
|
||||
if (ext != NULL && strcmp (ext, ".db") == 0)
|
||||
__libc_utmp_jump_table = &__libc_utmp_db_functions;
|
||||
else
|
||||
__libc_utmp_jump_table = &unknown_functions;
|
||||
|
||||
result = 0;
|
||||
}
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
weak_alias (__utmpname, utmpname)
|
||||
|
@ -23,7 +23,11 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <utmp.h>
|
||||
|
||||
|
||||
#ifndef _LIBC
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
/* Return the result of ttyname in the buffer pointed to by TTY, which should
|
||||
be of length BUF_LEN. If it is too long to fit in this buffer, a
|
||||
sufficiently long buffer is allocated using malloc, and returned in TTY.
|
||||
@ -135,20 +139,5 @@ login (const struct utmp *ut)
|
||||
}
|
||||
|
||||
/* Update the WTMP file. Here we have to add a new entry. */
|
||||
if (utmpname (_PATH_WTMP) != 0)
|
||||
{
|
||||
struct utmp *up;
|
||||
|
||||
/* Open the WTMP file. */
|
||||
setutent ();
|
||||
|
||||
/* Position at end of file. */
|
||||
while (! getutent_r (&utbuf, &up));
|
||||
|
||||
/* Write the new entry. */
|
||||
pututline (©);
|
||||
|
||||
/* Close WTMP file. */
|
||||
endutent ();
|
||||
}
|
||||
updwtmp (_PATH_WTMP, ©);
|
||||
}
|
||||
|
@ -17,53 +17,12 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
void
|
||||
updwtmp (const char *wtmp_file, const struct utmp *ut)
|
||||
{
|
||||
struct stat st;
|
||||
size_t written;
|
||||
int fd;
|
||||
|
||||
/* Open WTMP file. */
|
||||
fd = __open (wtmp_file, O_WRONLY | O_APPEND);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
/* Try to lock the file. */
|
||||
if (__flock (fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS)
|
||||
{
|
||||
/* Oh, oh. The file is already locked. Wait a bit and try again. */
|
||||
sleep (1);
|
||||
|
||||
/* This time we ignore the error. */
|
||||
__flock (fd, LOCK_EX | LOCK_NB);
|
||||
}
|
||||
|
||||
/* Remember original size of log file: */
|
||||
if (__fstat (fd, &st) < 0)
|
||||
goto done;
|
||||
|
||||
/* Write the entry. If we can't write all the bytes, reset the file
|
||||
size back to the original size. That way, no partial entries
|
||||
will remain. */
|
||||
written = __write (fd, ut, sizeof (struct utmp));
|
||||
if (written > 0 && written != sizeof (struct utmp))
|
||||
ftruncate (fd, st.st_size);
|
||||
|
||||
done:
|
||||
/* And unlock the file. */
|
||||
__flock (fd, LOCK_UN);
|
||||
|
||||
/* Close WTMP file. */
|
||||
__close (fd);
|
||||
}
|
||||
|
||||
void
|
||||
logwtmp (const char *line, const char *name, const char *host)
|
||||
@ -90,5 +49,5 @@ logwtmp (const char *line, const char *name, const char *host)
|
||||
time (&ut.ut_time);
|
||||
#endif
|
||||
|
||||
updwtmp(_PATH_WTMP, &ut);
|
||||
updwtmp (_PATH_WTMP, &ut);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* pty.h - Functions for pseudo TTY handling.
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -22,6 +22,7 @@
|
||||
#define _PTY_H 1
|
||||
#include <features.h>
|
||||
|
||||
#include <ioctl-types.h>
|
||||
#include <termios.h>
|
||||
|
||||
|
||||
|
46
login/updwtmp.c
Normal file
46
login/updwtmp.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
void
|
||||
updwtmp (const char *wtmp_file, const struct utmp *utmp)
|
||||
{
|
||||
/* See whether utmpd is running. */
|
||||
if ((*__libc_utmp_daemon_functions.updwtmp) (wtmp_file, utmp) < 0)
|
||||
{
|
||||
/* Use the normal file, but if the current file is _PATH_UTMP or
|
||||
_PATH_WTMP and the corresponding extended file (with an extra
|
||||
'x' added to the pathname) exists, we use the extended file,
|
||||
because the original file is in a different format. */
|
||||
if (strcmp (wtmp_file, _PATH_UTMP) == 0
|
||||
&& __access (_PATH_UTMP "x", F_OK) == 0)
|
||||
(*__libc_utmp_file_functions.updwtmp) (_PATH_UTMP "x", utmp);
|
||||
else if (strcmp (wtmp_file, _PATH_WTMP) == 0
|
||||
&& __access (_PATH_WTMP "x", F_OK) == 0)
|
||||
(*__libc_utmp_file_functions.updwtmp) (_PATH_WTMP "x", utmp);
|
||||
else
|
||||
(*__libc_utmp_file_functions.updwtmp) (wtmp_file, utmp);
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,21 @@ struct utfuncs
|
||||
int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **);
|
||||
struct utmp *(*pututline) (const struct utmp *);
|
||||
void (*endutent) (void);
|
||||
int (*utmpname) (const char *);
|
||||
|
||||
int (*updwtmp) (const char *, const struct utmp *);
|
||||
};
|
||||
|
||||
/* The tables from the services. */
|
||||
extern struct utfuncs __libc_utmp_file_functions;
|
||||
extern struct utfuncs __libc_utmp_daemon_functions;
|
||||
extern struct utfuncs __libc_utmp_unknown_functions;
|
||||
|
||||
/* Currently selected backend. */
|
||||
extern struct utfuncs *__libc_utmp_jump_table;
|
||||
|
||||
/* Current file name. */
|
||||
extern const char *__libc_utmp_file_name;
|
||||
|
||||
#endif /* utmp-private.h */
|
||||
|
||||
|
||||
|
||||
|
11
login/utmp.h
11
login/utmp.h
@ -49,21 +49,22 @@ extern void login __P ((__const struct utmp *__entry));
|
||||
/* Write the utmp entry to say the user on UT_LINE has logged out. */
|
||||
extern int logout __P ((__const char *__ut_line));
|
||||
|
||||
/* Append the given entry to a wtmp file. */
|
||||
extern void updwtmp __P ((__const char *__wtmp_file,
|
||||
__const struct utmp *__entry));
|
||||
|
||||
/* Append to wtmp an entry for the current time and the given info. */
|
||||
extern void logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
|
||||
__const char *__ut_host));
|
||||
|
||||
/* Append entry UTMP to the wtmp-like file WTMP_FILE. */
|
||||
extern void updwtmp __P ((__const char *__wtmp_file,
|
||||
__const struct utmp *__utmp));
|
||||
|
||||
/* Change name of the utmp file to be examined. */
|
||||
extern int __utmpname __P ((__const char *__file));
|
||||
extern int utmpname __P ((__const char *__file));
|
||||
|
||||
/* Read next entry from a utmp-like file. */
|
||||
extern struct utmp *getutent __P ((void));
|
||||
|
||||
/* Rest the input stream to the beginning of the file. */
|
||||
/* Reset the input stream to the beginning of the file. */
|
||||
extern void __setutent __P ((void));
|
||||
extern void setutent __P ((void));
|
||||
|
||||
|
454
login/utmp_daemon.c
Normal file
454
login/utmp_daemon.c
Normal file
@ -0,0 +1,454 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "utmp-private.h"
|
||||
#include "utmpd/utmpd.h"
|
||||
|
||||
#ifndef _LIBC
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
|
||||
/* Descriptor for the socket. */
|
||||
static int daemon_sock = INT_MIN;
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_daemon (int reset);
|
||||
static int getutent_r_daemon (struct utmp *buffer, struct utmp **result);
|
||||
static int getutid_r_daemon (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static int getutline_r_daemon (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_daemon (const struct utmp *utmp);
|
||||
static void endutent_daemon (void);
|
||||
static int updwtmp_daemon (const char *file, const struct utmp *utmp);
|
||||
|
||||
/* Jump table for daemon functions. */
|
||||
struct utfuncs __libc_utmp_daemon_functions =
|
||||
{
|
||||
setutent_daemon,
|
||||
getutent_r_daemon,
|
||||
getutid_r_daemon,
|
||||
getutline_r_daemon,
|
||||
pututline_daemon,
|
||||
endutent_daemon,
|
||||
updwtmp_daemon
|
||||
};
|
||||
|
||||
static int do_setutent (int sock);
|
||||
static int do_getutent (int sock, struct utmp *buffer);
|
||||
static int do_endutent (int sock);
|
||||
static int do_getutline (int sock, const struct utmp *line,
|
||||
struct utmp *buffer);
|
||||
static int do_getutid (int sock, const struct utmp *id,
|
||||
struct utmp *buffer);
|
||||
static int do_pututline (int sock, const struct utmp *utmp);
|
||||
static int do_updwtmp (int sock, const char *file,
|
||||
const struct utmp *utmp);
|
||||
|
||||
static int open_socket (const char *name);
|
||||
static int send_request (int sock, const request_header *request,
|
||||
reply_header *reply);
|
||||
|
||||
|
||||
static int
|
||||
setutent_daemon (int reset)
|
||||
{
|
||||
if (daemon_sock == INT_MIN)
|
||||
{
|
||||
daemon_sock = open_socket (_PATH_UTMPD_RW);
|
||||
if (daemon_sock < 0)
|
||||
{
|
||||
/* Hhm, read-write access did not work. Try read-only. */
|
||||
daemon_sock = open_socket (_PATH_UTMPD_RO);
|
||||
if (daemon_sock < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_setutent (daemon_sock) < 0)
|
||||
return 0;
|
||||
}
|
||||
else if (reset)
|
||||
{
|
||||
/* Send request to the daemon. */
|
||||
if (do_setutent (daemon_sock) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_daemon (void)
|
||||
{
|
||||
if (daemon_sock >= 0)
|
||||
{
|
||||
/* Send request to the daemon. */
|
||||
do_endutent (daemon_sock);
|
||||
close (daemon_sock);
|
||||
}
|
||||
|
||||
daemon_sock = INT_MIN;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutent_r_daemon (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
/* Open connection if not already done. */
|
||||
if (daemon_sock == INT_MIN)
|
||||
setutent_daemon (1);
|
||||
|
||||
if (daemon_sock < 0)
|
||||
{
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_getutent (daemon_sock, buffer) < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;;
|
||||
}
|
||||
|
||||
*result = buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutline_r_daemon (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
if (daemon_sock < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_getutline (daemon_sock, line, buffer) < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;;
|
||||
}
|
||||
|
||||
*result = buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutid_r_daemon (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
if (daemon_sock < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_getutid (daemon_sock, id, buffer) < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*result = buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct utmp *
|
||||
pututline_daemon (const struct utmp *utmp)
|
||||
{
|
||||
if (daemon_sock == INT_MIN)
|
||||
/* The connection is closed. Open it again. */
|
||||
setutent_daemon (0);
|
||||
|
||||
if (daemon_sock < 0)
|
||||
/* Something went wrong. */
|
||||
return NULL;
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_pututline (daemon_sock, utmp) < 0)
|
||||
return NULL;
|
||||
|
||||
return (struct utmp *)utmp;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
updwtmp_daemon (const char *file, const struct utmp *utmp)
|
||||
{
|
||||
int sock;
|
||||
|
||||
/* Only try to open for both reading and writing. */
|
||||
sock = open_socket (_PATH_UTMPD_RW);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
/* Send request to the daemon. */
|
||||
if (do_updwtmp (sock, file, utmp) < 0)
|
||||
return -1;
|
||||
|
||||
close (sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_setutent (int sock)
|
||||
{
|
||||
setutent_request request;
|
||||
setutent_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (setutent_request);
|
||||
request.header.type = UTMPD_REQ_SETUTENT;
|
||||
strncpy (request.file, __libc_utmp_file_name, sizeof request.file);
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (setutent_reply);
|
||||
reply.header.type = UTMPD_REQ_SETUTENT;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_getutent (int sock, struct utmp *buffer)
|
||||
{
|
||||
getutent_request request;
|
||||
getutent_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (getutent_request);
|
||||
request.header.type = UTMPD_REQ_GETUTENT;
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutent_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTENT;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
else
|
||||
memcpy (buffer, &reply.entry, sizeof (struct utmp));
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_endutent (int sock)
|
||||
{
|
||||
endutent_request request;
|
||||
endutent_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (endutent_request);
|
||||
request.header.type = UTMPD_REQ_ENDUTENT;
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (endutent_reply);
|
||||
reply.header.type = UTMPD_REQ_ENDUTENT;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_getutline (int sock, const struct utmp *line, struct utmp *buffer)
|
||||
{
|
||||
getutline_request request;
|
||||
getutline_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (getutline_request);
|
||||
request.header.type = UTMPD_REQ_GETUTLINE;
|
||||
memcpy (&request.line, line, sizeof (struct utmp));
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutline_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTLINE;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
else
|
||||
memcpy (buffer, &reply.entry, sizeof (struct utmp));
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_getutid (int sock, const struct utmp *id, struct utmp *buffer)
|
||||
{
|
||||
getutid_request request;
|
||||
getutid_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (getutid_request);
|
||||
request.header.type = UTMPD_REQ_GETUTID;
|
||||
memcpy (&request.id, id, sizeof (struct utmp));
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutid_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTID;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
else
|
||||
memcpy (buffer, &reply.entry, sizeof (struct utmp));
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_pututline (int sock, const struct utmp *utmp)
|
||||
{
|
||||
pututline_request request;
|
||||
pututline_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (pututline_request);
|
||||
request.header.type = UTMPD_REQ_PUTUTLINE;
|
||||
memcpy (&request.utmp, utmp, sizeof (struct utmp));
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (pututline_reply);
|
||||
reply.header.type = UTMPD_REQ_PUTUTLINE;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_updwtmp (int sock, const char *file, const struct utmp *utmp)
|
||||
{
|
||||
updwtmp_request request;
|
||||
updwtmp_reply reply;
|
||||
|
||||
request.header.version = UTMPD_VERSION;
|
||||
request.header.size = sizeof (updwtmp_request);
|
||||
request.header.type = UTMPD_REQ_UPDWTMP;
|
||||
strncpy (request.file, file, sizeof request.file);
|
||||
memcpy (&request.utmp, utmp, sizeof (struct utmp));
|
||||
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (updwtmp_reply);
|
||||
reply.header.type = UTMPD_REQ_UPDWTMP;
|
||||
|
||||
if (send_request (sock, &request.header, &reply.header) < 0)
|
||||
return -1;
|
||||
|
||||
if (reply.result < 0)
|
||||
__set_errno (reply.errnum);
|
||||
|
||||
return reply.result;
|
||||
}
|
||||
|
||||
|
||||
/* Create a socket connected to NAME. */
|
||||
static int
|
||||
open_socket (const char *name)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int sock;
|
||||
|
||||
sock = socket (PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
strcpy (addr.sun_path, name);
|
||||
if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
|
||||
{
|
||||
close (sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* Send REQUEST to SOCK, and wait for reply. Returns 0 if successful,
|
||||
storing the reply in REPLY, and -1 if not. */
|
||||
static int
|
||||
send_request (int sock, const request_header *request,
|
||||
reply_header *reply)
|
||||
{
|
||||
reply_header header;
|
||||
ssize_t nbytes;
|
||||
|
||||
nbytes = write (sock, request, request->size);
|
||||
if (nbytes != (ssize_t) request->size)
|
||||
return -1;
|
||||
|
||||
nbytes = read (sock, &header, sizeof (reply_header));
|
||||
if (nbytes != sizeof (reply_header))
|
||||
return -1;
|
||||
|
||||
if (reply->version != header.version
|
||||
|| reply->size != header.size
|
||||
|| reply->type != header.type)
|
||||
return -1;
|
||||
|
||||
nbytes = read (sock, reply + 1, reply->size - sizeof (reply_header));
|
||||
if (nbytes != (ssize_t) (reply->size - sizeof (reply_header)))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
104
login/utmp_db.c
104
login/utmp_db.c
@ -1,104 +0,0 @@
|
||||
/* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>
|
||||
and Paul Janzen <pcj@primenet.com>, 1996.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <db.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utmp.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
/* This is the default name. */
|
||||
static const char default_file_name[] = _PATH_UTMP_DB;
|
||||
|
||||
/* Current file name. */
|
||||
static const char *file_name = (const char *) default_file_name;
|
||||
|
||||
/* Descriptor for database. */
|
||||
#if 0
|
||||
/* XXX One day this will become meaningful again. */
|
||||
static DB *db_fd;
|
||||
static char last_date[16];
|
||||
#endif
|
||||
|
||||
/* Our local functions. */
|
||||
static int setutent_db (int reset);
|
||||
static void endutent_db (void);
|
||||
static int utmpname_db (const char *name);
|
||||
|
||||
|
||||
/* The jump table for the local functions. */
|
||||
struct utfuncs __libc_utmp_db_functions =
|
||||
{
|
||||
setutent_db,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
endutent_db,
|
||||
utmpname_db
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
setutent_db (int reset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_db (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
utmpname_db (const char *name)
|
||||
{
|
||||
if (strcmp (name, file_name) != 0)
|
||||
{
|
||||
if (strcmp (name, default_file_name) == 0)
|
||||
{
|
||||
if (file_name != default_file_name)
|
||||
free ((char *) file_name);
|
||||
|
||||
file_name = default_file_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *new_name = __strdup (name);
|
||||
if (new_name == NULL)
|
||||
/* Out of memory. */
|
||||
return -1;
|
||||
|
||||
if (file_name != default_file_name)
|
||||
free ((char *) file_name);
|
||||
|
||||
file_name = new_name;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -31,12 +31,11 @@
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
#ifndef _LIBC
|
||||
#define _(msg) (msg)
|
||||
#define __set_errno(val) errno = (val)
|
||||
#endif
|
||||
|
||||
/* This is the default name. */
|
||||
static const char default_file_name[] = _PATH_UTMP;
|
||||
|
||||
/* Current file name. */
|
||||
static const char *file_name = (const char *) default_file_name;
|
||||
|
||||
/* Descriptor for the file and position. */
|
||||
static int file_fd = INT_MIN;
|
||||
@ -44,6 +43,7 @@ static off_t file_offset;
|
||||
|
||||
static struct utmp last_entry;
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_file (int reset);
|
||||
static int getutent_r_file (struct utmp *buffer, struct utmp **result);
|
||||
@ -53,8 +53,7 @@ static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_file (const struct utmp *data);
|
||||
static void endutent_file (void);
|
||||
static int utmpname_file (const char *name);
|
||||
|
||||
static int updwtmp_file (const char *file, const struct utmp *utmp);
|
||||
|
||||
/* Jump table for file functions. */
|
||||
struct utfuncs __libc_utmp_file_functions =
|
||||
@ -65,7 +64,7 @@ struct utfuncs __libc_utmp_file_functions =
|
||||
getutline_r_file,
|
||||
pututline_file,
|
||||
endutent_file,
|
||||
utmpname_file
|
||||
updwtmp_file
|
||||
};
|
||||
|
||||
|
||||
@ -74,11 +73,11 @@ setutent_file (int reset)
|
||||
{
|
||||
if (file_fd == INT_MIN)
|
||||
{
|
||||
file_fd = open (file_name, O_RDWR);
|
||||
file_fd = open (__libc_utmp_file_name, O_RDWR);
|
||||
if (file_fd == -1)
|
||||
{
|
||||
/* Hhm, read-write access did not work. Try read-only. */
|
||||
file_fd = open (file_name, O_RDONLY);
|
||||
file_fd = open (__libc_utmp_file_name, O_RDONLY);
|
||||
if (file_fd == -1)
|
||||
{
|
||||
perror (_("while opening UTMP file"));
|
||||
@ -231,9 +230,7 @@ proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
|
||||
&&
|
||||
#endif
|
||||
#if _HAVE_UT_ID - 0
|
||||
(entry->ut_id[0] && match->ut_id[0]
|
||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
: strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
|
||||
strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
#else
|
||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
||||
#endif
|
||||
@ -404,29 +401,50 @@ pututline_file (const struct utmp *data)
|
||||
|
||||
|
||||
static int
|
||||
utmpname_file (const char *name)
|
||||
updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
{
|
||||
if (strcmp (name, file_name) != 0)
|
||||
int result = -1;
|
||||
struct stat st;
|
||||
ssize_t nbytes;
|
||||
int fd;
|
||||
|
||||
/* Open WTMP file. */
|
||||
fd = __open (file, O_WRONLY | O_APPEND);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
/* Try to lock the file. */
|
||||
if (__flock (fd, LOCK_EX | LOCK_NB) < 0 && errno != ENOSYS)
|
||||
{
|
||||
if (strcmp (name, default_file_name) == 0)
|
||||
{
|
||||
if (file_name != default_file_name)
|
||||
free ((char *) file_name);
|
||||
/* Oh, oh. The file is already locked. Wait a bit and try again. */
|
||||
sleep (1);
|
||||
|
||||
file_name = default_file_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *new_name = __strdup (name);
|
||||
if (new_name == NULL)
|
||||
/* Out of memory. */
|
||||
return -1;
|
||||
|
||||
if (file_name != default_file_name)
|
||||
free ((char *) file_name);
|
||||
|
||||
file_name = new_name;
|
||||
}
|
||||
/* This time we ignore the error. */
|
||||
__flock (fd, LOCK_EX | LOCK_NB);
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* Remember original size of log file. */
|
||||
if (__fstat (fd, &st) < 0)
|
||||
goto fail;
|
||||
|
||||
/* Write the entry. If we can't write all the bytes, reset the file
|
||||
size back to the original size. That way, no partial entries
|
||||
will remain. */
|
||||
nbytes = __write (fd, utmp, sizeof (struct utmp));
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
ftruncate (fd, st.st_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
fail:
|
||||
/* And unlock the file. */
|
||||
__flock (fd, LOCK_UN);
|
||||
|
||||
/* Close WTMP file. */
|
||||
__close (fd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
180
login/utmpd/connection.c
Normal file
180
login/utmpd/connection.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utmpd-private.h"
|
||||
|
||||
|
||||
/* Prototypes for the local functions. */
|
||||
static client_connection *alloc_connection (void);
|
||||
static void free_connection (client_connection *connection);
|
||||
static int set_nonblock_flag (int desc, int value);
|
||||
|
||||
|
||||
/* The head of the connection list. */
|
||||
static client_connection *connection_list = NULL;
|
||||
|
||||
|
||||
/* Accept connection on SOCK, with access permissions given by ACCESS.
|
||||
Returns a pointer to a newly allocated client_connection if
|
||||
successful, NULL if not. */
|
||||
client_connection *
|
||||
accept_connection (int sock, int access)
|
||||
{
|
||||
client_connection *connection;
|
||||
|
||||
connection = alloc_connection ();
|
||||
if (connection == NULL)
|
||||
return NULL;
|
||||
|
||||
connection->sock = accept (sock, NULL, NULL);
|
||||
connection->access = access;
|
||||
if (connection->sock < 0)
|
||||
{
|
||||
free_connection (connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (set_nonblock_flag (connection->sock, 1) < 0)
|
||||
{
|
||||
close_connection (connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
/* Close CONNECTION. */
|
||||
void
|
||||
close_connection (client_connection *connection)
|
||||
{
|
||||
close (connection->sock);
|
||||
free_connection (connection);
|
||||
}
|
||||
|
||||
|
||||
/* Return the connection for SOCK. */
|
||||
client_connection *
|
||||
find_connection (int sock)
|
||||
{
|
||||
client_connection *connection;
|
||||
|
||||
for (connection = connection_list; connection;
|
||||
connection = connection->next)
|
||||
{
|
||||
if (connection->sock == sock)
|
||||
return connection;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static client_connection *
|
||||
alloc_connection (void)
|
||||
{
|
||||
client_connection *connection;
|
||||
size_t read_bufsize = 1024;
|
||||
size_t write_bufsize = 1024;
|
||||
|
||||
connection = (client_connection *)malloc (sizeof (client_connection));
|
||||
if (connection == NULL)
|
||||
return NULL;
|
||||
|
||||
memset (connection, 0, sizeof (client_connection));
|
||||
|
||||
/* Allocate read buffer. */
|
||||
connection->read_base = malloc (read_bufsize);
|
||||
connection->read_ptr = connection->read_base;
|
||||
connection->read_end = connection->read_base + read_bufsize;
|
||||
if (connection->read_base == NULL)
|
||||
{
|
||||
free (connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate write buffer. */
|
||||
connection->write_base = malloc (write_bufsize);
|
||||
connection->write_ptr = connection->write_base;
|
||||
connection->write_end = connection->write_base + write_bufsize;
|
||||
if (connection->write_base == NULL)
|
||||
{
|
||||
free (connection->read_base);
|
||||
free (connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Link connection. */
|
||||
connection->next = connection_list;
|
||||
connection_list = connection;
|
||||
if (connection->next)
|
||||
connection->next->prev = connection;
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_connection (client_connection *connection)
|
||||
{
|
||||
/* Unlink connection. */
|
||||
if (connection->next)
|
||||
connection->next->prev = connection->prev;
|
||||
if (connection->prev)
|
||||
connection->prev->next = connection->next;
|
||||
|
||||
/* Take care of the head of the list. */
|
||||
if (connection == connection_list)
|
||||
connection_list = connection->next;
|
||||
|
||||
/* Free buffers. */
|
||||
if (connection->read_base)
|
||||
free (connection->read_base);
|
||||
if (connection->write_base)
|
||||
free (connection->write_base);
|
||||
|
||||
free (connection);
|
||||
}
|
||||
|
||||
|
||||
/* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
|
||||
or clear the flag if VALUE is 0.
|
||||
Return 0 on success, or -1 on error with `errno' set. */
|
||||
static int
|
||||
set_nonblock_flag (int desc, int value)
|
||||
{
|
||||
int oldflags = fcntl (desc, F_GETFL, 0);
|
||||
/* If reading the flags failed, return error indication now. */
|
||||
if (oldflags == -1)
|
||||
return -1;
|
||||
/* Set just the flag we want to set. */
|
||||
if (value != 0)
|
||||
oldflags |= O_NONBLOCK;
|
||||
else
|
||||
oldflags &= ~O_NONBLOCK;
|
||||
/* Store modified flag word in the descriptor. */
|
||||
return fcntl (desc, F_SETFL, oldflags);
|
||||
}
|
516
login/utmpd/database.c
Normal file
516
login/utmpd/database.c
Normal file
@ -0,0 +1,516 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
|
||||
#include "utmpd-private.h"
|
||||
#include "xtmp.h"
|
||||
|
||||
|
||||
/* Prototypes for the local functions. */
|
||||
static int initialize_database (utmp_database *database);
|
||||
static int store_state_entry (utmp_database *database, int old_position,
|
||||
const struct utmp *old_entry);
|
||||
static int store_process_entry (utmp_database *database, int old_position,
|
||||
const struct utmp *old_entry);
|
||||
static int replace_entry (utmp_database *database, int old_position,
|
||||
int new_position, const struct utmp *entry);
|
||||
static int store_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry);
|
||||
static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
|
||||
static int get_mtime (const char *file, time_t *timer);
|
||||
|
||||
|
||||
/* Open the database specified by FILE and merge it with the
|
||||
contents of the old format file specified by OLD_FILE. Returns a
|
||||
pointer to a newly allocated structure describing the database, or
|
||||
NULL on error. */
|
||||
utmp_database *
|
||||
open_database (const char *file, const char *old_file)
|
||||
{
|
||||
utmp_database *database;
|
||||
|
||||
/* Allocate memory. */
|
||||
database = (utmp_database *) malloc (sizeof (utmp_database));
|
||||
if (database == NULL)
|
||||
return NULL;
|
||||
|
||||
memset (database, 0, sizeof (utmp_database));
|
||||
|
||||
/* Open database. */
|
||||
database->fd = open (file, O_RDWR);
|
||||
if (database->fd < 0)
|
||||
goto fail;
|
||||
|
||||
database->old_fd = open (old_file, O_RDWR);
|
||||
if (database->old_fd < 0)
|
||||
goto fail;
|
||||
|
||||
if ((file && !(database->file = strdup (file)))
|
||||
|| (old_file && !(database->old_file = strdup (old_file))))
|
||||
goto fail;
|
||||
|
||||
if (initialize_database (database) < 0
|
||||
|| synchronize_database (database) < 0)
|
||||
goto fail;
|
||||
|
||||
return database;
|
||||
|
||||
fail:
|
||||
close_database (database);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Synchronize DATABASE. */
|
||||
int
|
||||
synchronize_database (utmp_database *database)
|
||||
{
|
||||
assert (database);
|
||||
|
||||
/* Check if there is a file in the old format, that we have to
|
||||
synchronize with. */
|
||||
if (database->old_file)
|
||||
{
|
||||
time_t curtime;
|
||||
time_t mtime;
|
||||
|
||||
curtime = time (NULL);
|
||||
|
||||
if (get_mtime (database->old_file, &mtime) < 0)
|
||||
return -1;
|
||||
|
||||
if (mtime >= database->mtime)
|
||||
{
|
||||
int position = 0;
|
||||
struct utmp entry;
|
||||
struct utmp old_entry;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (read_old_entry (database, position, &old_entry) < 0)
|
||||
break;
|
||||
|
||||
if (read_entry (database, position, &entry) < 0
|
||||
|| !compare_entry (&old_entry, &entry))
|
||||
{
|
||||
if (write_entry (database, position, &old_entry) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
position++;
|
||||
}
|
||||
|
||||
database->mtime = curtime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Close DATABASE. */
|
||||
void
|
||||
close_database (utmp_database *database)
|
||||
{
|
||||
assert (database);
|
||||
|
||||
if (database->fd >= 0)
|
||||
close (database->fd);
|
||||
|
||||
if (database->old_fd >= 0)
|
||||
close (database->old_fd);
|
||||
|
||||
/* Free allocated memory. */
|
||||
if (database->file)
|
||||
free (database->file);
|
||||
if (database->old_file)
|
||||
free (database->old_file);
|
||||
free (database);
|
||||
}
|
||||
|
||||
|
||||
/* Read the entry at POSITION in DATABASE and store the result in
|
||||
ENTRY. Returns 0 if successful, -1 if not. */
|
||||
int
|
||||
read_entry (utmp_database *database, int position, struct utmp *entry)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
off_t offset;
|
||||
|
||||
offset = position * sizeof (struct utmp);
|
||||
if (lseek (database->fd, offset, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
nbytes = read (database->fd, entry, sizeof (struct utmp));
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Write ENTRY at POSITION in DATABASE. Returns 0 if successful, -1
|
||||
on error. */
|
||||
int
|
||||
write_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry)
|
||||
{
|
||||
int result = -1;
|
||||
struct flock fl;
|
||||
ssize_t nbytes;
|
||||
off_t offset;
|
||||
|
||||
/* Try to lock the file. */
|
||||
memset (&fl, 0, sizeof (struct flock));
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fcntl (database->fd, F_SETLKW, &fl);
|
||||
|
||||
offset = position * sizeof (struct utmp);
|
||||
if (lseek (database->fd, offset, SEEK_SET) < 0)
|
||||
goto fail;
|
||||
|
||||
nbytes = write (database->fd, entry, sizeof (struct utmp));
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
ftruncate (database->fd, offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
fail:
|
||||
/* And unlock the file. */
|
||||
fl.l_type = F_UNLCK;
|
||||
fcntl (database->fd, F_SETLKW, &fl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Append ENTRY to DATABASE. Returns the position of the appended
|
||||
entry if successful, or -1 on error. */
|
||||
int
|
||||
append_entry (utmp_database *database, const struct utmp *entry)
|
||||
{
|
||||
int result = -1;
|
||||
struct flock fl;
|
||||
ssize_t nbytes;
|
||||
off_t offset;
|
||||
|
||||
/* Try to lock the file. */
|
||||
memset (&fl, 0, sizeof (struct flock));
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fcntl (database->fd, F_SETLKW, &fl);
|
||||
|
||||
offset = lseek (database->fd, 0, SEEK_END);
|
||||
if (offset % sizeof (struct utmp) != 0)
|
||||
{
|
||||
offset -= offset % sizeof (struct utmp);
|
||||
ftruncate (database->fd, offset);
|
||||
|
||||
if (lseek (database->fd, 0, SEEK_END) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nbytes = write (database->fd, entry, sizeof (struct utmp));
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
ftruncate (database->fd, offset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = offset / sizeof (struct utmp);
|
||||
|
||||
fail:
|
||||
/* And unlock the file. */
|
||||
fl.l_type = F_UNLCK;
|
||||
fcntl (database->fd, F_SETLKW, &fl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
read_old_entry (utmp_database *database, int position,
|
||||
struct utmp *entry)
|
||||
{
|
||||
struct xtmp old_entry;
|
||||
ssize_t nbytes;
|
||||
off_t offset;
|
||||
|
||||
offset = position * sizeof (struct xtmp);
|
||||
if (lseek (database->old_fd, offset, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
nbytes = read (database->old_fd, &old_entry, sizeof (struct xtmp));
|
||||
if (nbytes != sizeof (struct xtmp))
|
||||
return -1;
|
||||
|
||||
xtmp_to_utmp (&old_entry, entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
write_old_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry)
|
||||
{
|
||||
struct xtmp old_entry;
|
||||
ssize_t nbytes;
|
||||
off_t offset;
|
||||
|
||||
utmp_to_xtmp (entry, &old_entry);
|
||||
|
||||
offset = position * sizeof (struct xtmp);
|
||||
if (lseek (database->old_fd, offset, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
nbytes = write (database->old_fd, &old_entry, sizeof (struct xtmp));
|
||||
if (nbytes != sizeof (struct xtmp))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize DATABASE. */
|
||||
static int
|
||||
initialize_database (utmp_database *database)
|
||||
{
|
||||
struct utmp entry;
|
||||
int position = 0;
|
||||
|
||||
assert (database);
|
||||
|
||||
/* Check if there is a file in the old format to read. */
|
||||
if (database->old_file)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (read_old_entry (database, position, &entry) < 0)
|
||||
break;
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
/* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
|
||||
NEW_TIME, search for an entry of the same type in the
|
||||
database, and replace it if the entry in the file is newer. */
|
||||
if (entry.ut_type == RUN_LVL || entry.ut_type == BOOT_TIME
|
||||
|| entry.ut_type == OLD_TIME || entry.ut_type == NEW_TIME)
|
||||
{
|
||||
if (store_state_entry (database, position, &entry) < 0)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (store_process_entry (database, position, &entry) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update position. */
|
||||
position++;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (read_entry (database, position, &entry) < 0)
|
||||
break;
|
||||
|
||||
if (write_old_entry (database, position, &entry) < 0)
|
||||
return -1;
|
||||
|
||||
/* Update position. */
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
store_state_entry (utmp_database *database, int old_position,
|
||||
const struct utmp *old_entry)
|
||||
{
|
||||
struct utmp new_entry;
|
||||
int new_position = 0;
|
||||
int found = 0;
|
||||
|
||||
assert (old_entry->ut_type == RUN_LVL
|
||||
|| old_entry->ut_type == BOOT_TIME
|
||||
|| old_entry->ut_type == OLD_TIME
|
||||
|| old_entry->ut_type == NEW_TIME);
|
||||
|
||||
while (!found)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (read_entry (database, new_position, &new_entry) < 0)
|
||||
break;
|
||||
|
||||
if (old_entry->ut_type == new_entry.ut_type)
|
||||
{
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update position. */
|
||||
new_position++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
const struct utmp *entry;
|
||||
|
||||
if (old_entry->ut_time > new_entry.ut_time)
|
||||
entry = old_entry;
|
||||
else
|
||||
entry = &new_entry;
|
||||
|
||||
return replace_entry (database, old_position, new_position, entry);
|
||||
}
|
||||
|
||||
return store_entry (database, old_position, old_entry);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
store_process_entry (utmp_database *database, int old_position,
|
||||
const struct utmp *old_entry)
|
||||
{
|
||||
struct utmp new_entry;
|
||||
int new_position = 0;
|
||||
int found = 0;
|
||||
|
||||
while (!found)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (read_entry (database, new_position, &new_entry) < 0)
|
||||
break;
|
||||
|
||||
if (proc_utmp_eq (old_entry, &new_entry))
|
||||
{
|
||||
found = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update position. */
|
||||
new_position++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
const struct utmp *entry;
|
||||
|
||||
if (old_entry->ut_time > new_entry.ut_time)
|
||||
entry = old_entry;
|
||||
else
|
||||
entry = &new_entry;
|
||||
|
||||
return replace_entry (database, old_position, new_position, entry);
|
||||
}
|
||||
|
||||
return store_entry (database, old_position, old_entry);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
replace_entry (utmp_database *database, int old_position, int new_position,
|
||||
const struct utmp *entry)
|
||||
{
|
||||
struct utmp tmp;
|
||||
|
||||
if (read_entry (database, old_position, &tmp) < 0
|
||||
|| write_entry (database, old_position, entry) < 0
|
||||
|| write_entry (database, new_position, &tmp) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
store_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry)
|
||||
{
|
||||
struct utmp tmp;
|
||||
|
||||
if (read_entry (database, position, &tmp) < 0)
|
||||
return write_entry (database, position, entry);
|
||||
|
||||
if (write_entry (database, position, entry) < 0
|
||||
|| append_entry (database, &tmp) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function is identical to the one in login/utmp_file.c. */
|
||||
static int
|
||||
proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
|
||||
{
|
||||
return
|
||||
(
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
(match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
#if _HAVE_UT_ID - 0
|
||||
strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
#else
|
||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Get modification time of FILE and put it in TIMER. returns 0 if
|
||||
successful, -1 if not. */
|
||||
static int
|
||||
get_mtime (const char *file, time_t *timer)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat (file, &st) < 0)
|
||||
return -1;
|
||||
|
||||
*timer = st.st_mtime;
|
||||
|
||||
return 0;
|
||||
}
|
104
login/utmpd/error.c
Normal file
104
login/utmpd/error.c
Normal file
@ -0,0 +1,104 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "utmpd-private.h"
|
||||
|
||||
|
||||
/* This variable indicates if we have forked. If set, we log messages
|
||||
via the system logger. Otherwise we simply print the program name
|
||||
and the message to standard error. */
|
||||
int forked = 0;
|
||||
|
||||
|
||||
/* Log error message MESSAGE, which is a printf-style format string
|
||||
with optional args.
|
||||
If ERRNUM is nonzero, also log its corresponding system error message.
|
||||
Exit with status STATUS if it is nonzero. */
|
||||
void
|
||||
error (int status, int errnum, const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *buffer = NULL;
|
||||
|
||||
va_start (ap, message);
|
||||
vasprintf (&buffer, message, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (forked)
|
||||
{
|
||||
if (errnum == 0)
|
||||
syslog (LOG_ERR, "%s", buffer);
|
||||
else
|
||||
syslog (LOG_ERR, "%s: %s", buffer, strerror (errnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errnum == 0)
|
||||
fprintf (stderr, "%s: %s\n", program_invocation_name, buffer);
|
||||
else
|
||||
fprintf (stderr, "%s: %s: %s\n", program_invocation_name, buffer,
|
||||
strerror (errnum));
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
|
||||
if (status)
|
||||
exit (status);
|
||||
}
|
||||
|
||||
/* Log warning message MESSAGE, which is a printf-style format string
|
||||
with optional args.
|
||||
If ERRNUM is nonzero, also log its corresponding system error message. */
|
||||
void
|
||||
warning (int errnum, const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *buffer = NULL;
|
||||
|
||||
va_start (ap, message);
|
||||
vasprintf (&buffer, message, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (forked)
|
||||
{
|
||||
if (errnum == 0)
|
||||
syslog (LOG_WARNING, "%s", buffer);
|
||||
else
|
||||
syslog (LOG_WARNING, "%s: %s", buffer, strerror (errnum));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errnum == 0)
|
||||
printf ("%s: %s\n", program_invocation_name, buffer);
|
||||
else
|
||||
printf ("%s: %s: %s\n", program_invocation_name, buffer,
|
||||
strerror (errnum));
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
}
|
650
login/utmpd/request.c
Normal file
650
login/utmpd/request.c
Normal file
@ -0,0 +1,650 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "utmpd.h"
|
||||
#include "utmpd-private.h"
|
||||
|
||||
|
||||
/* Prototypes for the local functions. */
|
||||
static int process_request (client_connection *connection);
|
||||
static int send_reply (client_connection *connect, const reply_header *reply);
|
||||
|
||||
static int do_setutent (client_connection *connection);
|
||||
static int do_getutent (client_connection *connection);
|
||||
static int do_endutent (client_connection *connection);
|
||||
static int do_getutline (client_connection *connection);
|
||||
static int do_getutid (client_connection *connection);
|
||||
static int do_pututline (client_connection *connection);
|
||||
static int do_updwtmp (client_connection *connection);
|
||||
|
||||
static int proc_utmp_eq (const struct utmp *entry, const struct utmp *match);
|
||||
static int internal_getut_r (client_connection *connection,
|
||||
const struct utmp *id, struct utmp *buffer);
|
||||
|
||||
|
||||
/* Read data from the client on CONNECTION. */
|
||||
int
|
||||
read_data (client_connection *connection)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
|
||||
assert (connection);
|
||||
assert ((connection->read_end - connection->read_ptr) > 0);
|
||||
|
||||
/* Read data. */
|
||||
nbytes = read (connection->sock, connection->read_ptr,
|
||||
connection->read_end - connection->read_ptr);
|
||||
if (nbytes > 0)
|
||||
{
|
||||
size_t total_bytes;
|
||||
|
||||
/* Update read pointer. */
|
||||
connection->read_ptr += nbytes;
|
||||
|
||||
/* Check if we have a complete request header. */
|
||||
total_bytes = connection->read_ptr - connection->read_base;
|
||||
if (total_bytes >= sizeof (request_header))
|
||||
{
|
||||
request_header *header;
|
||||
|
||||
/* Check if we have a complete request. */
|
||||
header = (request_header *)connection->read_base;
|
||||
if (total_bytes >= header->size)
|
||||
{
|
||||
/* Process the request. */
|
||||
if (process_request (connection) < 0)
|
||||
return -1;
|
||||
|
||||
/* Adjust read pointer, and flush buffer. */
|
||||
connection->read_ptr -= header->size;
|
||||
memmove (connection->read_base,
|
||||
connection->read_base + header->size,
|
||||
connection->read_ptr - connection->read_base);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nbytes < 0)
|
||||
error (0, errno, "cannot read from client");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Write data to the client on CONNECTION. */
|
||||
int
|
||||
write_data (client_connection *connection)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
|
||||
assert (connection);
|
||||
assert ((connection->write_ptr - connection->write_base) > 0);
|
||||
|
||||
/* Write data. */
|
||||
nbytes = write (connection->sock, connection->write_base,
|
||||
connection->write_ptr - connection->write_base);
|
||||
if (nbytes > 0)
|
||||
{
|
||||
/* Adjust write pointer and flush buffer. */
|
||||
connection->write_ptr -= nbytes;
|
||||
memmove (connection->write_base, connection->write_base + nbytes,
|
||||
connection->write_ptr - connection->write_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nbytes < 0)
|
||||
error (0, errno, "cannot write to client");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Process the request received on CONNECTION. Returns 0 if
|
||||
successful, -1 if not. */
|
||||
static int
|
||||
process_request (client_connection *connection)
|
||||
{
|
||||
request_header *header;
|
||||
|
||||
assert (connection);
|
||||
assert (connection->read_base);
|
||||
|
||||
header = (request_header *)connection->read_base;
|
||||
if (header->version != UTMPD_VERSION)
|
||||
{
|
||||
warning (EINVAL, "invalid protocol version");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (header->type)
|
||||
{
|
||||
case UTMPD_REQ_SETUTENT: return do_setutent (connection);
|
||||
case UTMPD_REQ_GETUTENT: return do_getutent (connection);
|
||||
case UTMPD_REQ_ENDUTENT: return do_endutent (connection);
|
||||
case UTMPD_REQ_GETUTLINE: return do_getutline (connection);
|
||||
case UTMPD_REQ_GETUTID: return do_getutid (connection);
|
||||
case UTMPD_REQ_PUTUTLINE: return do_pututline (connection);
|
||||
case UTMPD_REQ_UPDWTMP: return do_updwtmp (connection);
|
||||
default:
|
||||
warning (EINVAL, "invalid request type");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Send the reply specified by HEADER to the client on CONNECTION.
|
||||
Returns 0 if successful, -1 if not. */
|
||||
static int
|
||||
send_reply (client_connection *connection, const reply_header *reply)
|
||||
{
|
||||
/* Check if the reply fits in the buffer. */
|
||||
if ((size_t) (connection->write_end - connection->write_ptr) < reply->size)
|
||||
{
|
||||
error (0, 0, "buffer overflow");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy reply to buffer, and adjust write pointer. */
|
||||
memcpy (connection->write_ptr, reply, reply->size);
|
||||
connection->write_ptr += reply->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_setutent (client_connection *connection)
|
||||
{
|
||||
setutent_request *request;
|
||||
setutent_reply reply;
|
||||
|
||||
request = (setutent_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (setutent_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (setutent_reply);
|
||||
reply.header.type = UTMPD_REQ_SETUTENT;
|
||||
|
||||
/* Select database. */
|
||||
if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
|
||||
connection->database = utmp_db;
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Initialize position pointer. */
|
||||
connection->position = 0;
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
/* Make sure the entry won't match. */
|
||||
connection->last_entry.ut_type = -1;
|
||||
#endif
|
||||
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
return send_reply (connection, &reply.header);
|
||||
|
||||
return_error:
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_getutent (client_connection *connection)
|
||||
{
|
||||
getutent_request *request;
|
||||
getutent_reply reply;
|
||||
|
||||
request = (getutent_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (getutent_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutent_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTENT;
|
||||
|
||||
if (connection->database == NULL || connection->position == -1)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Make sure we're in synch with the ordinary file. */
|
||||
if (synchronize_database (connection->database) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Read the next entry from the database. */
|
||||
if (read_entry (connection->database, connection->position,
|
||||
&connection->last_entry) < 0)
|
||||
{
|
||||
connection->position = -1;
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Update position pointer. */
|
||||
connection->position++;
|
||||
|
||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
return send_reply (connection, (reply_header *)&reply);
|
||||
|
||||
return_error:
|
||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_endutent (client_connection *connection)
|
||||
{
|
||||
endutent_request *request;
|
||||
endutent_reply reply;
|
||||
|
||||
request = (endutent_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (endutent_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Deselect database. */
|
||||
connection->database = NULL;
|
||||
|
||||
/* Formulate reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (endutent_reply);
|
||||
reply.header.type = UTMPD_REQ_ENDUTENT;
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_getutline (client_connection *connection)
|
||||
{
|
||||
getutline_request *request;
|
||||
getutline_reply reply;
|
||||
|
||||
request = (getutline_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (getutline_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutline_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTLINE;
|
||||
|
||||
if (connection->database == NULL || connection->position == -1)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Make sure we're in synch with the ordinary file. */
|
||||
if (synchronize_database (connection->database) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (read_entry (connection->database, connection->position,
|
||||
&connection->last_entry) < 0)
|
||||
{
|
||||
connection->position = -1;
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
connection->position++;
|
||||
|
||||
/* Stop if we found a user or login entry. */
|
||||
if (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(connection->last_entry.ut_type == USER_PROCESS
|
||||
|| connection->last_entry.ut_type == LOGIN_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
!strncmp (request->line.ut_line, connection->last_entry.ut_line,
|
||||
sizeof request->line.ut_line))
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
return send_reply (connection, &reply.header);
|
||||
|
||||
return_error:
|
||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_getutid (client_connection *connection)
|
||||
{
|
||||
getutid_request *request;
|
||||
getutid_reply reply;
|
||||
|
||||
request = (getutid_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (getutid_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (getutid_reply);
|
||||
reply.header.type = UTMPD_REQ_GETUTID;
|
||||
|
||||
if (connection->database == NULL || connection->position == -1)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Make sure we're in synch with the ordinary file. */
|
||||
if (synchronize_database (connection->database) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
if (internal_getut_r (connection, &request->id,
|
||||
&connection->last_entry) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
memcpy (&reply.entry, &connection->last_entry, sizeof (struct utmp));
|
||||
return send_reply (connection, &reply.header);
|
||||
|
||||
return_error:
|
||||
memset (&reply.entry, 0, sizeof (struct utmp));
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_pututline (client_connection *connection)
|
||||
{
|
||||
pututline_request *request;
|
||||
pututline_reply reply;
|
||||
struct utmp buffer;
|
||||
int found;
|
||||
|
||||
request = (pututline_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (pututline_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (pututline_reply);
|
||||
reply.header.type = UTMPD_REQ_PUTUTLINE;
|
||||
|
||||
if (!(connection->access & W_OK))
|
||||
{
|
||||
errno = EPERM;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
if (connection->database == NULL || connection->position == -1)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Make sure we're in synch with the ordinary file. */
|
||||
if (synchronize_database (connection->database) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Find the correct place to insert the data. */
|
||||
if (connection->position > 0
|
||||
&& (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(connection->last_entry.ut_type == request->utmp.ut_type
|
||||
&& (connection->last_entry.ut_type == RUN_LVL
|
||||
|| connection->last_entry.ut_type == BOOT_TIME
|
||||
|| connection->last_entry.ut_type == OLD_TIME
|
||||
|| connection->last_entry.ut_type == NEW_TIME))
|
||||
||
|
||||
#endif
|
||||
proc_utmp_eq (&connection->last_entry, &request->utmp)))
|
||||
found = 1;
|
||||
else
|
||||
found = internal_getut_r (connection, &request->utmp, &buffer);
|
||||
|
||||
if (found < 0)
|
||||
{
|
||||
/* We append the next entry. */
|
||||
connection->position =
|
||||
append_entry (connection->database, &request->utmp);
|
||||
if (connection->position < 0)
|
||||
goto return_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We replace the just read entry. */
|
||||
connection->position--;
|
||||
if (write_entry (connection->database, connection->position,
|
||||
&request->utmp) < 0)
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Write the entry to the compatibility file. */
|
||||
write_old_entry (connection->database, connection->position, &request->utmp);
|
||||
|
||||
/* Update position pointer. */
|
||||
connection->position++;
|
||||
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
return send_reply (connection, &reply.header);
|
||||
|
||||
return_error:
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_updwtmp (client_connection *connection)
|
||||
{
|
||||
updwtmp_request *request;
|
||||
updwtmp_reply reply;
|
||||
utmp_database *database;
|
||||
|
||||
request = (updwtmp_request *)connection->read_base;
|
||||
if (request->header.size != sizeof (updwtmp_request))
|
||||
{
|
||||
warning (EINVAL, "invalid request size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize reply. */
|
||||
reply.header.version = UTMPD_VERSION;
|
||||
reply.header.size = sizeof (updwtmp_reply);
|
||||
reply.header.type = UTMPD_REQ_UPDWTMP;
|
||||
|
||||
if (!(connection->access & W_OK))
|
||||
{
|
||||
errno = EPERM;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Select database. */
|
||||
if (!strncmp (request->file, _PATH_UTMP, sizeof request->file))
|
||||
database = utmp_db;
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Make sure we're in synch with the ordinary file. */
|
||||
if (synchronize_database (database) < 0)
|
||||
{
|
||||
errno = ESRCH;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* Append the entry. */
|
||||
if (append_entry (database, &request->utmp) < 0)
|
||||
goto return_error;
|
||||
|
||||
reply.errnum = 0;
|
||||
reply.result = 0;
|
||||
return send_reply (connection, &reply.header);
|
||||
|
||||
return_error:
|
||||
reply.errnum = errno;
|
||||
reply.result = -1;
|
||||
return send_reply (connection, &reply.header);
|
||||
}
|
||||
|
||||
|
||||
/* This function is identical to the one in login/utmp_file.c. */
|
||||
static int
|
||||
proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
|
||||
{
|
||||
return
|
||||
(
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
(match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
#if _HAVE_UT_ID - 0
|
||||
strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
#else
|
||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* This function is derived from the one in login/utmp_file.c. */
|
||||
static int
|
||||
internal_getut_r (client_connection *connection,
|
||||
const struct utmp *id, struct utmp *buffer)
|
||||
{
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
|
||||
|| id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
|
||||
{
|
||||
/* Search for next entry with type RUN_LVL, BOOT_TIME,
|
||||
OLD_TIME, or NEW_TIME. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (read_entry (connection->database, connection->position,
|
||||
buffer) < 0)
|
||||
{
|
||||
connection->position = -1;
|
||||
return -1;
|
||||
}
|
||||
connection->position++;
|
||||
|
||||
if (id->ut_type == buffer->ut_type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* _HAVE_UT_TYPE */
|
||||
{
|
||||
/* Search for the next entry with the specified ID and with type
|
||||
INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (read_entry (connection->database, connection->position,
|
||||
buffer) < 0)
|
||||
{
|
||||
connection->position = -1;
|
||||
return -1;
|
||||
}
|
||||
connection->position++;
|
||||
|
||||
if (proc_utmp_eq (buffer, id))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
107
login/utmpd/utmpd-private.h
Normal file
107
login/utmpd/utmpd-private.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _UTMPD_PRIVATE_H
|
||||
#define _UTMPD_PRIVATE_H 1
|
||||
|
||||
#include <time.h>
|
||||
#include <utmp.h>
|
||||
|
||||
|
||||
/* The number of connections we allow. */
|
||||
#ifndef MAX_CONNECTIONS
|
||||
#define MAX_CONNECTIONS 16
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct utmp_database
|
||||
{
|
||||
int fd;
|
||||
int old_fd;
|
||||
char *file;
|
||||
char *old_file;
|
||||
time_t mtime;
|
||||
} utmp_database;
|
||||
|
||||
|
||||
/* The databases we handle. */
|
||||
extern utmp_database *utmp_db;
|
||||
extern utmp_database *wtmp_db;
|
||||
|
||||
|
||||
typedef struct client_connection
|
||||
{
|
||||
int sock;
|
||||
/* Access permissions. */
|
||||
int access;
|
||||
|
||||
/* Read pointer. */
|
||||
void *read_base;
|
||||
void *read_ptr;
|
||||
void *read_end;
|
||||
|
||||
/* Write buffer. */
|
||||
void *write_base;
|
||||
void *write_ptr;
|
||||
void *write_end;
|
||||
|
||||
/* Database to use for this connection. */
|
||||
utmp_database *database;
|
||||
/* Position pointer. */
|
||||
int position;
|
||||
|
||||
/* Last read entry. */
|
||||
struct utmp last_entry;
|
||||
|
||||
/* Pointers to the next and previous connections in the list. */
|
||||
struct client_connection *next;
|
||||
struct client_connection *prev;
|
||||
} client_connection;
|
||||
|
||||
|
||||
/* This variable indicates if we have forked. If set, we log messages
|
||||
via the system logger. Otherwise we simply print the program name
|
||||
and the message to standard error. */
|
||||
extern int forked;
|
||||
|
||||
|
||||
/* Database functions. */
|
||||
utmp_database *open_database (const char *file, const char *old_file);
|
||||
int synchronize_database (utmp_database *database);
|
||||
void close_database (utmp_database *database);
|
||||
int read_entry (utmp_database *database, int position, struct utmp *entry);
|
||||
int write_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry);
|
||||
int append_entry (utmp_database *database, const struct utmp *entry);
|
||||
int read_old_entry (utmp_database *database, int position, struct utmp *entry);
|
||||
int write_old_entry (utmp_database *database, int position,
|
||||
const struct utmp *entry);
|
||||
|
||||
/* Connection oriented functions. */
|
||||
client_connection *accept_connection (int sock, int access);
|
||||
client_connection *find_connection (int sock);
|
||||
void close_connection (client_connection *connection);
|
||||
int read_data (client_connection *connection);
|
||||
int write_data (client_connection *connection);
|
||||
|
||||
void error (int status, int errnum, const char *message, ...);
|
||||
void warning (int errnum, const char *message, ...);
|
||||
|
||||
#endif /* utmpd-private.h */
|
||||
|
384
login/utmpd/utmpd.c
Normal file
384
login/utmpd/utmpd.c
Normal file
@ -0,0 +1,384 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <pwd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utmpd.h"
|
||||
#include "utmpd-private.h"
|
||||
|
||||
/* Get libc version number. */
|
||||
#include "../../version.h"
|
||||
|
||||
#define PACKAGE "libc"
|
||||
|
||||
/* Long options. */
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{ "debug", no_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* The UTMP database. */
|
||||
utmp_database *utmp_db;
|
||||
|
||||
/* The socket for read only requests. */
|
||||
int ro_sock = -1;
|
||||
|
||||
/* The socket for read/write requests. */
|
||||
int rw_sock = -1;
|
||||
|
||||
|
||||
/* Prototypes for the local functions. */
|
||||
static void usage (int status) __attribute__ ((noreturn));
|
||||
static void drop_priviliges (void);
|
||||
static int make_socket (const char *name);
|
||||
static void handle_requests (void) __attribute__ ((noreturn));
|
||||
static void termination_handler (int signum);
|
||||
static int check_pid (const char *file);
|
||||
static int write_pid (const char *file);
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
mode_t mask;
|
||||
int debug;
|
||||
int do_help;
|
||||
int do_version;
|
||||
int opt;
|
||||
|
||||
/* Initialize local variables. */
|
||||
debug = 0;
|
||||
do_help = 0;
|
||||
do_version = 0;
|
||||
|
||||
while ((opt = getopt_long (argc, argv, "dhV", long_options, NULL)) != -1)
|
||||
switch (opt)
|
||||
{
|
||||
case '\0': /* Long option. */
|
||||
break;
|
||||
case 'h':
|
||||
do_help = 1;
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'V':
|
||||
do_version = 1;
|
||||
break;
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Version information is reequested. */
|
||||
if (do_version)
|
||||
{
|
||||
printf ("utmpd (GNU %s) %s\n", PACKAGE, VERSION);
|
||||
printf (gettext ("\
|
||||
Copyright (C) %s Free Software Foundation, Inc.\n\
|
||||
This is free software; see the source for copying conditions. There is NO\n\
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
||||
"), "1997");
|
||||
printf (gettext ("Written by %s.\n"), "Mark Kettenis");
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Help is requested. */
|
||||
if (do_help)
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
signal (SIGINT, termination_handler);
|
||||
signal (SIGTERM, termination_handler);
|
||||
|
||||
/* Check if we are already running. */
|
||||
if (check_pid (_PATH_UTMPDPID))
|
||||
error (EXIT_FAILURE, 0, "already running");
|
||||
|
||||
/* Open UTMP database. */
|
||||
utmp_db = open_database (_PATH_UTMP "x", _PATH_UTMP);
|
||||
if (utmp_db == NULL)
|
||||
error (EXIT_FAILURE, errno, "%s", _PATH_UTMP);
|
||||
|
||||
/* Create sockets, with the right permissions. */
|
||||
mask = umask (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||
ro_sock = make_socket (_PATH_UTMPD_RO);
|
||||
umask (S_IXUSR | S_IRWXG | S_IRWXO);
|
||||
rw_sock = make_socket (_PATH_UTMPD_RW);
|
||||
umask (mask);
|
||||
|
||||
/* Set the sockets up to accept connections. */
|
||||
if (listen (ro_sock, MAX_CONNECTIONS) < 0
|
||||
|| listen (rw_sock, MAX_CONNECTIONS) < 0)
|
||||
error (EXIT_FAILURE, errno, "cannot enable socket to accept connections");
|
||||
|
||||
/* Behave like a daemon. */
|
||||
if (!debug)
|
||||
{
|
||||
openlog ("utmpd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
|
||||
|
||||
if (daemon (0, 0) < 0)
|
||||
error (EXIT_FAILURE, errno, "cannot auto-background");
|
||||
forked = 1;
|
||||
|
||||
if (write_pid (_PATH_UTMPDPID) < 0)
|
||||
warning (errno, "%s", _PATH_UTMPDPID);
|
||||
}
|
||||
|
||||
/* Drop priviliges. */
|
||||
drop_priviliges ();
|
||||
|
||||
/* Handle incoming requests. */
|
||||
handle_requests ();
|
||||
}
|
||||
|
||||
|
||||
/* Display usage information and exit. */
|
||||
static void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
|
||||
program_invocation_name);
|
||||
else
|
||||
{
|
||||
printf (gettext ("\
|
||||
Usage: %s [OPTION]...\n\
|
||||
-d, --debug do not fork and display messages on the current tty\n\
|
||||
-h, --help display this help and exit\n\
|
||||
-V, --version output version information and exit\n"),
|
||||
program_invocation_name);
|
||||
fputs (gettext ("\
|
||||
Report bugs to <kettenis@phys.uva.nl>.\n"),
|
||||
stdout);
|
||||
}
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
|
||||
/* Drop priviliges. */
|
||||
static void
|
||||
drop_priviliges (void)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
pw = getpwnam ("daemon");
|
||||
if (pw)
|
||||
{
|
||||
seteuid (pw->pw_uid);
|
||||
setegid (pw->pw_gid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Make a socket in the file namespace using the filename NAME as the
|
||||
socket's address. */
|
||||
static int
|
||||
make_socket (const char *name)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
size_t size;
|
||||
int sock;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket (PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
error (EXIT_FAILURE, errno, "cannot create socket");
|
||||
|
||||
/* Bind a name to the socket. */
|
||||
addr.sun_family = AF_UNIX;
|
||||
strcpy (addr.sun_path, name);
|
||||
|
||||
/* The size of the address is the offset of the start
|
||||
of the filename, plus its length, plus one for the
|
||||
terminating null byte. */
|
||||
size = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (addr.sun_path));
|
||||
|
||||
if (bind (sock, (struct sockaddr *) &addr, size) < 0)
|
||||
error (EXIT_FAILURE, errno, "%s", name);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/* Hanlde incoming requests. */
|
||||
static
|
||||
void handle_requests (void)
|
||||
{
|
||||
client_connection *connection;
|
||||
fd_set active_read_fd_set;
|
||||
fd_set active_write_fd_set;
|
||||
fd_set read_fd_set;
|
||||
fd_set write_fd_set;
|
||||
int fd;
|
||||
|
||||
/* Initialize the set of active sockets. */
|
||||
FD_ZERO (&active_read_fd_set);
|
||||
FD_ZERO (&active_write_fd_set);
|
||||
FD_SET (rw_sock, &active_read_fd_set);
|
||||
FD_SET (ro_sock, &active_read_fd_set);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Block until input arrives on one or more active sockets. */
|
||||
read_fd_set = active_read_fd_set;
|
||||
write_fd_set = active_write_fd_set;
|
||||
if (select (FD_SETSIZE, &read_fd_set, &write_fd_set, NULL, NULL) < 0)
|
||||
error (EXIT_FAILURE, errno, "cannot get input on sockets");
|
||||
|
||||
/* Service all the sockets with input pending. */
|
||||
for (fd = 0; fd < FD_SETSIZE; fd++)
|
||||
{
|
||||
if (FD_ISSET (fd, &read_fd_set))
|
||||
{
|
||||
if (fd == ro_sock || fd == rw_sock)
|
||||
{
|
||||
int access = ((fd == rw_sock) ? (R_OK | W_OK) : R_OK);
|
||||
|
||||
connection = accept_connection (fd, access);
|
||||
if (connection == NULL)
|
||||
error (0, errno, "cannot accept connection");
|
||||
|
||||
FD_SET (connection->sock, &active_read_fd_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = find_connection (fd);
|
||||
if (connection == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find connection");
|
||||
|
||||
if (read_data (connection) < 0)
|
||||
{
|
||||
close_connection (connection);
|
||||
FD_CLR (fd, &active_read_fd_set);
|
||||
FD_CLR (fd, &active_write_fd_set);
|
||||
}
|
||||
|
||||
if (connection->write_ptr > connection->write_base)
|
||||
FD_SET (fd, &active_write_fd_set);
|
||||
}
|
||||
}
|
||||
if (FD_ISSET (fd, &write_fd_set) &&
|
||||
fd != rw_sock && fd != ro_sock)
|
||||
{
|
||||
connection = find_connection (fd);
|
||||
if (connection == NULL)
|
||||
error (EXIT_FAILURE, 0, "cannot find connection");
|
||||
|
||||
if (write_data (connection) < 0)
|
||||
{
|
||||
close_connection (connection);
|
||||
FD_CLR (fd, &active_read_fd_set);
|
||||
FD_CLR (fd, &active_write_fd_set);
|
||||
}
|
||||
|
||||
if (connection->write_ptr == connection->write_base)
|
||||
FD_CLR (fd, &active_write_fd_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Cleanup. */
|
||||
static void
|
||||
termination_handler (int signum)
|
||||
{
|
||||
/* Close sockets. */
|
||||
close (ro_sock);
|
||||
close (rw_sock);
|
||||
|
||||
/* Restore user id. */
|
||||
seteuid (getuid ());
|
||||
|
||||
/* Clean up the files created by `bind'. */
|
||||
unlink (_PATH_UTMPD_RO);
|
||||
unlink (_PATH_UTMPD_RW);
|
||||
|
||||
if (utmp_db)
|
||||
close_database (utmp_db);
|
||||
|
||||
/* Clean up pid file. */
|
||||
unlink (_PATH_UTMPDPID);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if the process in pid file FILE is running, 0 if not. */
|
||||
static int
|
||||
check_pid (const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (_PATH_UTMPDPID, "r");
|
||||
if (fp)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
fscanf (fp, "%d", &pid);
|
||||
fclose (fp);
|
||||
|
||||
if (kill (pid, 0) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write the current process id to the file FILE. Returns 0 if
|
||||
successful, -1 if not. */
|
||||
static int
|
||||
write_pid (const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (_PATH_UTMPDPID, "w");
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
|
||||
fprintf (fp, "%d\n", getpid ());
|
||||
if (ferror (fp))
|
||||
return -1;
|
||||
|
||||
fclose (fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
141
login/utmpd/utmpd.h
Normal file
141
login/utmpd/utmpd.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _UTMPD_H
|
||||
#define _UTMPD_H 1
|
||||
|
||||
/* This is an *internal* header. */
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <utmp.h>
|
||||
|
||||
|
||||
/* Paths to daemon sockets. */
|
||||
#define _PATH_UTMPD_RO "/var/run/utmpd.ro"
|
||||
#define _PATH_UTMPD_RW "/var/run/utmpd.rw"
|
||||
|
||||
|
||||
/* Path to PID file. */
|
||||
#define _PATH_UTMPDPID "/var/run/utmpd.pid"
|
||||
|
||||
|
||||
/* Version number of the daemon interface. */
|
||||
#define UTMPD_VERSION 1
|
||||
|
||||
|
||||
/* Services provided. */
|
||||
typedef enum
|
||||
{
|
||||
UTMPD_REQ_SETUTENT,
|
||||
UTMPD_REQ_GETUTENT,
|
||||
UTMPD_REQ_ENDUTENT,
|
||||
UTMPD_REQ_GETUTLINE,
|
||||
UTMPD_REQ_GETUTID,
|
||||
UTMPD_REQ_PUTUTLINE,
|
||||
UTMPD_REQ_UPDWTMP
|
||||
} request_type;
|
||||
|
||||
|
||||
/* Header common to all requests. */
|
||||
typedef struct
|
||||
{
|
||||
/* Version number of the daemon interface. */
|
||||
int version;
|
||||
/* Number of bytes in this request. */
|
||||
size_t size;
|
||||
/* Service requested. */
|
||||
request_type type;
|
||||
} request_header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
/* File to use. */
|
||||
char file[_POSIX_PATH_MAX + 1];
|
||||
} setutent_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
} getutent_request, endutent_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
/* Entry to match. */
|
||||
struct utmp line;
|
||||
} getutline_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
/* Entry to match. */
|
||||
struct utmp id;
|
||||
} getutid_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
/* Entry to write. */
|
||||
struct utmp utmp;
|
||||
} pututline_request;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
request_header header;
|
||||
/* File to use. */
|
||||
char file[_POSIX_PATH_MAX + 1];
|
||||
/* Entry to write. */
|
||||
struct utmp utmp;
|
||||
} updwtmp_request;
|
||||
|
||||
|
||||
/* Header common to all replies. */
|
||||
typedef struct
|
||||
{
|
||||
/* Version number of the daemon interface. */
|
||||
int version;
|
||||
/* Number of bytes in this reply. */
|
||||
size_t size;
|
||||
/* Answer to the request. */
|
||||
request_type type;
|
||||
} reply_header;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
reply_header header;
|
||||
/* Error code. */
|
||||
int errnum;
|
||||
/* Return value. */
|
||||
int result;
|
||||
} setutent_reply, endutent_reply, pututline_reply, updwtmp_reply;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
reply_header header;
|
||||
/* Found entry. */
|
||||
struct utmp entry;
|
||||
/* Error code. */
|
||||
int errnum;
|
||||
/* Return value. */
|
||||
int result;
|
||||
} getutent_reply, getutline_reply, getutid_reply;
|
||||
|
||||
#endif /* utmpd.h */
|
102
login/utmpd/xtmp.c
Normal file
102
login/utmpd/xtmp.c
Normal file
@ -0,0 +1,102 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "xtmp.h"
|
||||
|
||||
/* Convert the entry XT to the new utmp format and store it in UT.
|
||||
Fields in UT that were not present in the old utmp format are
|
||||
initialized to zero. */
|
||||
void
|
||||
xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp)
|
||||
{
|
||||
memset (utmp, 0, sizeof (struct utmp));
|
||||
#if _HAVE_XT_TYPE - 0
|
||||
utmp->ut_type = xtmp->xt_type;
|
||||
#endif
|
||||
#if _HAVE_XT_PID - 0
|
||||
utmp->ut_pid = xtmp->xt_pid;
|
||||
#endif
|
||||
strncpy (utmp->ut_line, xtmp->xt_line, XT_LINESIZE);
|
||||
#if _HAVE_XT_ID - 0
|
||||
strncpy (utmp->ut_id, xtmp->xt_id, sizeof xtmp->xt_id);
|
||||
#endif
|
||||
utmp->ut_time = xtmp->xt_time;
|
||||
strncpy (utmp->ut_user, xtmp->xt_user, XT_NAMESIZE);
|
||||
#if _HAVE_XT_HOST - 0
|
||||
strncpy (utmp->ut_host, xtmp->xt_host, XT_HOSTSIZE);
|
||||
#endif
|
||||
utmp->ut_addr = xtmp->xt_addr;
|
||||
}
|
||||
|
||||
/* Convert the entry UTMP to the old utmp format and store it in XTMP. */
|
||||
void
|
||||
utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp)
|
||||
{
|
||||
memset (xtmp, 0, sizeof (struct xtmp));
|
||||
#if _HAVE_XT_TYPE - 0
|
||||
xtmp->xt_type = utmp->ut_type;
|
||||
#endif
|
||||
#if _HAVE_XT_PID - 0
|
||||
xtmp->xt_pid = utmp->ut_pid;
|
||||
#endif
|
||||
strncpy (xtmp->xt_line, utmp->ut_line, XT_LINESIZE);
|
||||
xtmp->xt_line[XT_LINESIZE] = '\0';
|
||||
#if _HAVE_XT_ID - 0
|
||||
strncpy (xtmp->xt_id, utmp->ut_id, sizeof xtmp->xt_id);
|
||||
#endif
|
||||
xtmp->xt_time = utmp->ut_time;
|
||||
strncpy (xtmp->xt_user, utmp->ut_user, XT_NAMESIZE);
|
||||
#if _HAVE_XT_HOST - 0
|
||||
strncpy (xtmp->xt_host, utmp->ut_host, XT_HOSTSIZE);
|
||||
xtmp->xt_host[XT_HOSTSIZE] = '\0';
|
||||
#endif
|
||||
xtmp->xt_addr = utmp->ut_addr;
|
||||
}
|
||||
|
||||
/* Compare an old style entry XTMP with a new style entry UTMP. The
|
||||
function returns 1 if the information that is in both old and new
|
||||
style entries is identical. Otherwise this function returns 0. */
|
||||
int
|
||||
compare_entry (const struct utmp *xtmp, const struct utmp *utmp)
|
||||
{
|
||||
return
|
||||
(
|
||||
#if _HAVE_XT_TYPE - 0
|
||||
xtmp->ut_type == utmp->ut_type
|
||||
#endif
|
||||
#if _HAVE_XT_PID - 0
|
||||
&& xtmp->ut_pid == utmp->ut_pid
|
||||
#endif
|
||||
&& !strncmp (xtmp->ut_line, utmp->ut_line, XT_LINESIZE - 1)
|
||||
#if _HAVE_XT_ID - 0
|
||||
&& !strncmp (xtmp->ut_id, utmp->ut_id, sizeof utmp->ut_id)
|
||||
#endif
|
||||
&& xtmp->ut_time == utmp->ut_time
|
||||
&& !strncmp (xtmp->ut_user, utmp->ut_user, XT_NAMESIZE)
|
||||
#if _HAVE_XT_HOST - 0
|
||||
&& !strncmp (xtmp->ut_host, utmp->ut_host, XT_HOSTSIZE - 1)
|
||||
#endif
|
||||
&& xtmp->ut_addr == utmp->ut_addr);
|
||||
}
|
56
login/utmpd/xtmp.h
Normal file
56
login/utmpd/xtmp.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* The `struct xtmp' type, describing the old linux utmp format.
|
||||
Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _XTMP_H
|
||||
#define _XTMP_H 1
|
||||
#include <features.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#define XT_LINESIZE 12
|
||||
#define XT_NAMESIZE 8
|
||||
#define XT_HOSTSIZE 16
|
||||
|
||||
struct xtmp
|
||||
{
|
||||
short int xt_type; /* Type of login. */
|
||||
pid_t xt_pid; /* Pid of login process. */
|
||||
char xt_line[XT_LINESIZE]; /* NUL-terminated devicename of tty. */
|
||||
char xt_id[4]; /* Inittab id. */
|
||||
time_t xt_time; /* Time entry was made. */
|
||||
char xt_user[XT_NAMESIZE]; /* Username (not NUL terminated). */
|
||||
char xt_host[XT_HOSTSIZE]; /* Hostname for remote login. */
|
||||
long xt_addr; /* Internet adress of remote host. */
|
||||
};
|
||||
|
||||
#define _HAVE_XT_TYPE 1
|
||||
#define _HAVE_XT_PID 1
|
||||
#define _HAVE_XT_ID 1
|
||||
#define _HAVE_XT_HOST 1
|
||||
|
||||
|
||||
extern void xtmp_to_utmp (const struct xtmp *xtmp, struct utmp *utmp);
|
||||
extern void utmp_to_xtmp (const struct utmp *utmp, struct xtmp *xtmp);
|
||||
extern int compare_entry (const struct utmp *xtmp,
|
||||
const struct utmp *utmp);
|
||||
|
||||
#endif /* xtmp.h */
|
53
login/utmpdump.c
Normal file
53
login/utmpdump.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* utmpdump - dump utmp-like files.
|
||||
Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
void
|
||||
print_entry (struct utmp *up)
|
||||
{
|
||||
printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-15.15s] [%ld]\n",
|
||||
up->ut_type, up->ut_pid, up->ut_id, up->ut_user,
|
||||
up->ut_line, 4 + ctime (&up->ut_time), up->ut_tv.tv_usec);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct utmp *up;
|
||||
|
||||
if (argc > 1)
|
||||
utmpname (argv[1]);
|
||||
|
||||
setutent ();
|
||||
|
||||
while ((up = getutent ()))
|
||||
print_entry (up);
|
||||
|
||||
endutent ();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
86
login/utmpname.c
Normal file
86
login/utmpname.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#if _LIBC
|
||||
#include <libc-lock.h>
|
||||
#else
|
||||
#define __libc_lock_lock(NAME) ((void) 0)
|
||||
#define __libc_lock_unlock(NAME) ((void) 0)
|
||||
#define __libc_lock_define(CLASS,NAME)
|
||||
#define weak_alias(name, aliasname) \
|
||||
extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
/* This is the default name. */
|
||||
static const char default_file_name[] = _PATH_UTMP;
|
||||
|
||||
/* Current file name. */
|
||||
const char *__libc_utmp_file_name = (const char *) default_file_name;
|
||||
|
||||
/* We have to use the lock in getutent_r.c. */
|
||||
__libc_lock_define (extern, __libc_utmp_lock)
|
||||
|
||||
|
||||
int
|
||||
__utmpname (const char *file)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
/* Close the old file. */
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
|
||||
if (strcmp (file, __libc_utmp_file_name) != 0)
|
||||
{
|
||||
if (strcmp (file, default_file_name) == 0)
|
||||
{
|
||||
if (__libc_utmp_file_name != default_file_name)
|
||||
free ((char *) __libc_utmp_file_name);
|
||||
|
||||
__libc_utmp_file_name = default_file_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *file_name = __strdup (file);
|
||||
if (file_name == NULL)
|
||||
/* Out of memory. */
|
||||
goto done;
|
||||
|
||||
if (__libc_utmp_file_name != default_file_name)
|
||||
free ((char *) __libc_utmp_file_name);
|
||||
|
||||
__libc_utmp_file_name = file_name;
|
||||
}
|
||||
}
|
||||
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
result = 0;
|
||||
|
||||
done:
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
return result;
|
||||
}
|
||||
weak_alias (__utmpname, utmpname)
|
@ -74,19 +74,23 @@ long-c-yes = $(calls:=l)
|
||||
distribute += $(long-c-yes:=.c)
|
||||
|
||||
# Rules for the test suite.
|
||||
tests = test-float test-double $(test-longdouble-$(long-double-fcts))
|
||||
tests = test-float test-double $(test-longdouble-$(long-double-fcts)) \
|
||||
test-ifloat test-idouble
|
||||
# We do the `long double' tests only if this data type is available and
|
||||
# distrinct from `double'.
|
||||
#
|
||||
# XXX This test is disabled for now since the functions are too buggy.
|
||||
#test-longdouble-yes = test-longdouble
|
||||
#test-longdouble-yes = test-ldouble test-ildoubl
|
||||
|
||||
CFLAGS-test-float.c = -fno-inline
|
||||
CFLAGS-test-double.c = -fno-inline
|
||||
CFLAGS-test-longdouble.c = -fno-inline
|
||||
CFLAGS-test-ldouble.c = -fno-inline
|
||||
LDLIBS-test-ifloat = libm
|
||||
LDLIBS-test-idouble = libm
|
||||
LDLIBS-test-ildoubl = libm
|
||||
LDLIBS-test-float = libm
|
||||
LDLIBS-test-double = libm
|
||||
LDLIBS-test-longdouble = libm
|
||||
LDLIBS-test-ldouble = libm
|
||||
|
||||
distribute += libm-test.c
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* NOTE: Because of the special way this file is used by <math.h>, this
|
||||
/* NOTE: Because of the special way this file is used by <complex.h>, this
|
||||
file must NOT be protected from multiple inclusion as header files
|
||||
usually are.
|
||||
|
||||
|
307
math/libm-test.c
307
math/libm-test.c
@ -1,6 +1,6 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@arthur.pfalz.de>, 1997.
|
||||
Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
@ -39,30 +39,67 @@
|
||||
*/
|
||||
|
||||
/* This program isn't finished yet.
|
||||
It has tests for acos, acosh, asin, asinh, atan, atan2, atanh,
|
||||
It has tests for:
|
||||
acos, acosh, asin, asinh, atan, atan2, atanh,
|
||||
cbrt, ceil, copysign, cos, cosh, exp, exp2, expm1,
|
||||
fabs, fdim, floor, fmin, fmax, fpclassify,
|
||||
frexp, hypot, ilogb, ldexp,
|
||||
log, log10, log1p, log2, logb, modf, nextafter,
|
||||
pow, scalb, scalbn, sin, sinh, sqrt, tan, tanh, trunc.
|
||||
Tests for the other libm-functions will come later.
|
||||
pow, rint, rinttol, rinttoll, round, roundtol, roundtoll,
|
||||
scalb, scalbn, sin, sinh, sqrt, tan, tanh, trunc
|
||||
|
||||
and for the following complex math functions:
|
||||
cacos, cacosh, casin, casinh, catan, catanh,
|
||||
ccos, ccosh, cexp, clog, cpow, csin, csinh, csqrt, ctanh.
|
||||
|
||||
At the moment the following functions aren't tested:
|
||||
cabs, carg, conj, cproj, cimag, creal, drem,
|
||||
erf, erfc, gamma, lgamma,
|
||||
j0, j1, jn, y0, y1, yn,
|
||||
nearbyint, remainder, remquo, signbit, significant, sincos.
|
||||
|
||||
The routines using random variables are still under construction. I don't
|
||||
like it the way it's working now and will change it.
|
||||
|
||||
Exception handling has not been implemented so far so don't get fooled
|
||||
that these tests pass.
|
||||
|
||||
Parameter handling is primitive in the moment:
|
||||
--verbose=[0..3] for different levels of output:
|
||||
--verbose=[0..4] for different levels of output:
|
||||
0: only error count
|
||||
1: basic report on failed tests
|
||||
1: basic report on failed tests (default)
|
||||
2: full report on failed tests
|
||||
3: full report on failed and passed tests (default)
|
||||
-v for full output (equals --verbose=3)
|
||||
3: full report on failed and passed tests
|
||||
4: additional report on exceptions
|
||||
-v for full output (equals --verbose=4)
|
||||
-s,--silent outputs only the error count (equals --verbose=0)
|
||||
*/
|
||||
|
||||
/* "Philosophy":
|
||||
|
||||
This suite tests the correct implementation of mathematical
|
||||
functions in libm. Some simple, specific parameters are tested for
|
||||
correctness. Handling of specific inputs (e.g. infinity,
|
||||
not-a-number) is also tested. Correct handling of exceptions is
|
||||
checked against. These implemented tests should check all cases
|
||||
that are specified in ISO C 9X.
|
||||
|
||||
Inline functions: Inlining functions should give an improvement in
|
||||
speed - but not in precission. The inlined functions return
|
||||
reasonable values for a reasonable range of input values. The
|
||||
result is not necessarily correct for all values and exceptions are
|
||||
not correctly raised in all cases. Problematic input and return
|
||||
values are infinity, not-a-number and minus zero. This suite
|
||||
therefore does not check these specific inputs and the exception
|
||||
handling for inlined mathematical functions - just the "reasonable"
|
||||
values are checked.
|
||||
|
||||
Beware: The tests might fail for any of the following reasons:
|
||||
- Tests are wrong
|
||||
- Functions are wrong
|
||||
- Floating Point Unit not working properly
|
||||
- Compiler has errors
|
||||
|
||||
With e.g. gcc 2.7.2.2 the test for cexp fails because of a compiler error.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
@ -75,11 +112,8 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <getopt.h>
|
||||
|
||||
/* TEST_EXCEPTION: tests if an exception as occured */
|
||||
/* for the moment: does nothing */
|
||||
/* Possible exceptions */
|
||||
#define NO_EXCEPTION 0x0
|
||||
#define INVALID_EXCEPTION 0x1
|
||||
@ -167,11 +201,39 @@ random_greater (MATHTYPE min_value)
|
||||
}
|
||||
|
||||
/* Get a random value x with x < max_value. */
|
||||
#ifndef TEST_INLINE
|
||||
static MATHTYPE
|
||||
random_less (MATHTYPE max_value)
|
||||
{
|
||||
return random_value (-1e6, max_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
output_new_test (const char *test_name)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("\nTesting: %s\n", test_name);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
output_pass_value (void)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: Value Ok.\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
output_fail_value (const char * test_name)
|
||||
{
|
||||
if (verbose > 0 && verbose < 3)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
if (verbose >= 3)
|
||||
printf ("Fail:\n");
|
||||
}
|
||||
|
||||
|
||||
/* Test whether a given exception was raised. */
|
||||
@ -182,18 +244,22 @@ test_single_exception (const char *test_name,
|
||||
fexcept_t fe_flag,
|
||||
const char *flag_name)
|
||||
{
|
||||
#ifndef TEST_INLINE
|
||||
if (exception & exc_flag)
|
||||
{
|
||||
if (fetestexcept (fe_flag))
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s:\nException \"%s\" set\n", test_name, flag_name);
|
||||
if (verbose > 3)
|
||||
printf ("Pass: Exception \"%s\" set\n", flag_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s:\nException \"%s\" not set\n",
|
||||
if (verbose && verbose < 3)
|
||||
printf ("Fail: %s: Exception \"%s\" not set\n",
|
||||
test_name, flag_name);
|
||||
if (verbose >= 3)
|
||||
printf ("Fail: Exception \"%s\" not set\n",
|
||||
flag_name);
|
||||
++noErrors;
|
||||
}
|
||||
}
|
||||
@ -201,18 +267,22 @@ test_single_exception (const char *test_name,
|
||||
{
|
||||
if (fetestexcept (fe_flag))
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s:\nException \"%s\" set\n",
|
||||
if (verbose && verbose < 3)
|
||||
printf ("Fail: %s: Exception \"%s\" set\n",
|
||||
test_name, flag_name);
|
||||
if (verbose >= 3)
|
||||
printf ("Fail: Exception \"%s\" set\n",
|
||||
flag_name);
|
||||
++noErrors;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s:\nException \"%s\" not set\n",
|
||||
test_name, flag_name);
|
||||
if (verbose > 3)
|
||||
printf ("Pass: Exception \"%s\" not set\n",
|
||||
flag_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -256,6 +326,8 @@ test_exceptions (const char *test_name, short int exception)
|
||||
static int
|
||||
check_equal (MATHTYPE computed, MATHTYPE supplied, MATHTYPE eps, MATHTYPE * diff)
|
||||
{
|
||||
int ret_value;
|
||||
|
||||
/* Both plus Infinity or both minus infinity. */
|
||||
if (ISINF (computed) && (ISINF (computed) == ISINF (supplied)))
|
||||
return 1;
|
||||
@ -265,25 +337,28 @@ check_equal (MATHTYPE computed, MATHTYPE supplied, MATHTYPE eps, MATHTYPE * diff
|
||||
|
||||
*diff = FUNC(fabs) (computed - supplied);
|
||||
|
||||
if (*diff <= eps && (signbit (computed) == signbit (supplied) || eps != 0.0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
ret_value = (*diff <= eps &&
|
||||
(signbit (computed) == signbit (supplied) || eps != 0.0));
|
||||
|
||||
/* Make sure the subtraction/comparsion have no influence on the exceptions. */
|
||||
feclearexcept (FE_ALL_EXCEPT);
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
output_result_bool (const char *test_name, int result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
++noErrors;
|
||||
}
|
||||
|
||||
@ -297,13 +372,11 @@ output_isvalue (const char *test_name, int result,
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1)
|
||||
printf (" Value: %.20" PRINTF_EXPR "\n", value);
|
||||
noErrors++;
|
||||
@ -319,13 +392,11 @@ output_isvalue_ext (const char *test_name, int result,
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1)
|
||||
{
|
||||
printf (" Value: %.20" PRINTF_EXPR "\n", value);
|
||||
@ -346,13 +417,11 @@ output_result (const char *test_name, int result,
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1 && print_values)
|
||||
{
|
||||
printf ("Result:\n");
|
||||
@ -377,13 +446,11 @@ output_result_ext (const char *test_name, int result,
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1 && print_values)
|
||||
{
|
||||
printf ("Result:\n");
|
||||
@ -399,13 +466,16 @@ output_result_ext (const char *test_name, int result,
|
||||
fpstack_test (test_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are the same
|
||||
*/
|
||||
static void
|
||||
check (const char *test_name, MATHTYPE computed, MATHTYPE expected)
|
||||
{
|
||||
MATHTYPE diff;
|
||||
int result;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
result = check_equal (computed, expected, 0, &diff);
|
||||
output_result (test_name, result,
|
||||
@ -413,6 +483,10 @@ check (const char *test_name, MATHTYPE computed, MATHTYPE expected)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are the same,
|
||||
outputs the parameter to the function
|
||||
*/
|
||||
static void
|
||||
check_ext (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
MATHTYPE parameter)
|
||||
@ -420,6 +494,7 @@ check_ext (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
MATHTYPE diff;
|
||||
int result;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
result = check_equal (computed, expected, 0, &diff);
|
||||
output_result_ext (test_name, result,
|
||||
@ -427,6 +502,10 @@ check_ext (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are the same and
|
||||
checks also for exception flags
|
||||
*/
|
||||
static void
|
||||
check_exc (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
short exception)
|
||||
@ -434,13 +513,16 @@ check_exc (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
MATHTYPE diff;
|
||||
int result;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, exception);
|
||||
result = check_equal (computed, expected, 0, &diff);
|
||||
output_result (test_name, result,
|
||||
computed, expected, diff, PRINT, PRINT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are close enough
|
||||
*/
|
||||
static void
|
||||
check_eps (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
MATHTYPE epsilon)
|
||||
@ -448,38 +530,43 @@ check_eps (const char *test_name, MATHTYPE computed, MATHTYPE expected,
|
||||
MATHTYPE diff;
|
||||
int result;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
result = check_equal (computed, expected, epsilon, &diff);
|
||||
output_result (test_name, result,
|
||||
computed, expected, diff, PRINT, PRINT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check a boolean condition
|
||||
*/
|
||||
static void
|
||||
check_bool (const char *test_name, int computed)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_result_bool (test_name, computed);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are equal (long int values)
|
||||
*/
|
||||
static void
|
||||
check_long (const char *test_name, long int computed, long int expected)
|
||||
{
|
||||
long int diff = computed - expected;
|
||||
int result = diff == 0;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1)
|
||||
{
|
||||
printf ("Result:\n");
|
||||
@ -492,7 +579,9 @@ check_long (const char *test_name, long int computed, long int expected)
|
||||
fpstack_test (test_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed and expected values are equal (long long int values)
|
||||
*/
|
||||
static void
|
||||
check_longlong (const char *test_name, long long int computed,
|
||||
long long int expected)
|
||||
@ -500,17 +589,16 @@ check_longlong (const char *test_name, long long int computed,
|
||||
long long int diff = computed - expected;
|
||||
int result = diff == 0;
|
||||
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (verbose > 2)
|
||||
printf ("Pass: %s\n", test_name);
|
||||
output_pass_value ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
printf ("Fail: %s\n", test_name);
|
||||
output_fail_value (test_name);
|
||||
if (verbose > 1)
|
||||
{
|
||||
printf ("Result:\n");
|
||||
@ -523,46 +611,64 @@ check_longlong (const char *test_name, long long int computed,
|
||||
fpstack_test (test_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed value is not-a-number
|
||||
*/
|
||||
static void
|
||||
check_isnan (const char *test_name, MATHTYPE computed)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue (test_name, isnan (computed), computed);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed value is not-a-number and test for exceptions
|
||||
*/
|
||||
static void
|
||||
check_isnan_exc (const char *test_name, MATHTYPE computed,
|
||||
short exception)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, exception);
|
||||
output_isvalue (test_name, isnan (computed), computed);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed value is not-a-number and test for exceptions
|
||||
*/
|
||||
static void
|
||||
check_isnan_maybe_exc (const char *test_name, MATHTYPE computed,
|
||||
short exception)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_not_exception (test_name, exception);
|
||||
output_isvalue (test_name, isnan (computed), computed);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that computed value is not-a-number and supply parameter
|
||||
*/
|
||||
#ifndef TEST_INLINE
|
||||
static void
|
||||
check_isnan_ext (const char *test_name, MATHTYPE computed,
|
||||
MATHTYPE parameter)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue_ext (test_name, isnan (computed), computed, parameter);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Tests if computed is +Inf */
|
||||
static void
|
||||
check_isinfp (const char *test_name, MATHTYPE computed)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue (test_name, (ISINF (computed) == +1), computed);
|
||||
}
|
||||
@ -572,6 +678,7 @@ static void
|
||||
check_isinfp_ext (const char *test_name, MATHTYPE computed,
|
||||
MATHTYPE parameter)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue_ext (test_name, (ISINF (computed) == +1), computed, parameter);
|
||||
}
|
||||
@ -582,6 +689,7 @@ static void
|
||||
check_isinfp_exc (const char *test_name, MATHTYPE computed,
|
||||
int exception)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, exception);
|
||||
output_isvalue (test_name, (ISINF (computed) == +1), computed);
|
||||
}
|
||||
@ -590,18 +698,22 @@ check_isinfp_exc (const char *test_name, MATHTYPE computed,
|
||||
static void
|
||||
check_isinfn (const char *test_name, MATHTYPE computed)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue (test_name, (ISINF (computed) == -1), computed);
|
||||
}
|
||||
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
static void
|
||||
check_isinfn_ext (const char *test_name, MATHTYPE computed,
|
||||
MATHTYPE parameter)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, NO_EXCEPTION);
|
||||
output_isvalue_ext (test_name, (ISINF (computed) == -1), computed, parameter);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Tests if computed is -Inf */
|
||||
@ -609,6 +721,7 @@ static void
|
||||
check_isinfn_exc (const char *test_name, MATHTYPE computed,
|
||||
int exception)
|
||||
{
|
||||
output_new_test (test_name);
|
||||
test_exceptions (test_name, exception);
|
||||
output_isvalue (test_name, (ISINF (computed) == -1), computed);
|
||||
}
|
||||
@ -621,48 +734,59 @@ check_isinfn_exc (const char *test_name, MATHTYPE computed,
|
||||
static void
|
||||
acos_test (void)
|
||||
{
|
||||
#ifndef TEST_INLINE
|
||||
MATHTYPE x;
|
||||
|
||||
check ("acos (1) == 0", FUNC(acos) (1), 0);
|
||||
|
||||
x = random_greater (1);
|
||||
check_isnan_exc ("acos (x) == NaN plus invalid exception for |x| > 1",
|
||||
FUNC(acos) (x),
|
||||
INVALID_EXCEPTION);
|
||||
#endif
|
||||
|
||||
check ("acos (1) == 0", FUNC(acos) (1), 0);
|
||||
}
|
||||
|
||||
static void
|
||||
acosh_test (void)
|
||||
{
|
||||
#ifndef TEST_INLINE
|
||||
MATHTYPE x;
|
||||
|
||||
check ("acosh(1) == 0", FUNC(acosh) (1), 0);
|
||||
check_isinfp ("acosh(+inf) == +inf", FUNC(acosh) (plus_infty));
|
||||
|
||||
x = random_less (1);
|
||||
check_isnan_exc ("acosh(x) == NaN plus invalid exception if x < 1",
|
||||
FUNC(acosh) (x), INVALID_EXCEPTION);
|
||||
#endif
|
||||
|
||||
check ("acosh(1) == 0", FUNC(acosh) (1), 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
asin_test (void)
|
||||
{
|
||||
#ifndef TEST_INLINE
|
||||
MATHTYPE x;
|
||||
check ("asin (0) == 0", FUNC(asin) (0), 0);
|
||||
|
||||
x = random_greater (1);
|
||||
check_isnan_exc ("asin x == NaN plus invalid exception for |x| > 1",
|
||||
FUNC(asin) (x),
|
||||
INVALID_EXCEPTION);
|
||||
#endif
|
||||
|
||||
check ("asin (0) == 0", FUNC(asin) (0), 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
asinh_test (void)
|
||||
{
|
||||
|
||||
check ("asinh(+0) == +0", FUNC(asinh) (0), 0);
|
||||
#ifndef TEST_INLINE
|
||||
check ("asinh(-0) == -0", FUNC(asinh) (minus_zero), minus_zero);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -674,7 +798,6 @@ atan_test (void)
|
||||
|
||||
check ("atan (+inf) == pi/2", FUNC(atan) (plus_infty), M_PI_2);
|
||||
check ("atan (-inf) == -pi/2", FUNC(atan) (minus_infty), -M_PI_2);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -734,11 +857,14 @@ atanh_test (void)
|
||||
{
|
||||
|
||||
check ("atanh(+0) == +0", FUNC(atanh) (0), 0);
|
||||
#ifndef TEST_INLINE
|
||||
check ("atanh(-0) == -0", FUNC(atanh) (minus_zero), minus_zero);
|
||||
|
||||
check_isinfp_exc ("atanh(+1) == +inf plus divide-by-zero exception",
|
||||
FUNC(atanh) (1), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
check_isinfn_exc ("atanh(-1) == -inf plus divide-by-zero exception",
|
||||
FUNC(atanh) (-1), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -748,10 +874,11 @@ cbrt_test (void)
|
||||
check ("cbrt (+0) == +0", FUNC(cbrt) (0.0), 0.0);
|
||||
check ("cbrt (-0) == -0", FUNC(cbrt) (minus_zero), minus_zero);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check_isinfp ("cbrt (+inf) == +inf", FUNC(cbrt) (plus_infty));
|
||||
check_isinfn ("cbrt (-inf) == -inf", FUNC(cbrt) (minus_infty));
|
||||
check_isnan ("cbrt (NaN) == NaN", FUNC(cbrt) (nan_value));
|
||||
|
||||
#endif
|
||||
check_eps ("cbrt (8) == 2", FUNC(cbrt) (8), 2, CHOOSE (5e-17L, 0, 0));
|
||||
check_eps ("cbrt (-27) == -3", FUNC(cbrt) (-27.0), -3.0,
|
||||
CHOOSE (3e-16L, 0, 0));
|
||||
@ -797,8 +924,10 @@ cosh_test (void)
|
||||
check ("cosh (+0) == 1", FUNC(cosh) (0), 1);
|
||||
check ("cosh (-0) == 1", FUNC(cosh) (minus_zero), 1);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check_isinfp ("cosh (+inf) == +inf", FUNC(cosh) (plus_infty));
|
||||
check_isinfp ("cosh (-inf) == +inf", FUNC(cosh) (minus_infty));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -808,9 +937,10 @@ exp_test (void)
|
||||
check ("exp (+0) == 1", FUNC(exp) (0), 1);
|
||||
check ("exp (-0) == 1", FUNC(exp) (minus_zero), 1);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check_isinfp ("exp (+inf) == +inf", FUNC(exp) (plus_infty));
|
||||
check ("exp (-inf) == 0", FUNC(exp) (minus_infty), 0);
|
||||
|
||||
#endif
|
||||
check_eps ("exp (1) == e", FUNC(exp) (1), M_E, CHOOSE (4e-18L, 0, 0));
|
||||
}
|
||||
|
||||
@ -1207,10 +1337,13 @@ static void
|
||||
sinh_test (void)
|
||||
{
|
||||
check ("sinh (+0) == +0", FUNC(sinh) (0), 0);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check ("sinh (-0) == -0", FUNC(sinh) (minus_zero), minus_zero);
|
||||
|
||||
check_isinfp ("sinh (+inf) == +inf", FUNC(sinh) (plus_infty));
|
||||
check_isinfn ("sinh (-inf) == -inf", FUNC(sinh) (minus_infty));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1233,10 +1366,12 @@ static void
|
||||
tanh_test (void)
|
||||
{
|
||||
check ("tanh (+0) == +0", FUNC(tanh) (0), 0);
|
||||
#ifndef TEST_INLINE
|
||||
check ("tanh (-0) == -0", FUNC(tanh) (minus_zero), minus_zero);
|
||||
|
||||
check ("tanh (+inf) == +1", FUNC(tanh) (plus_infty), 1);
|
||||
check ("tanh (-inf) == -1", FUNC(tanh) (minus_infty), -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1311,6 +1446,7 @@ pow_test (void)
|
||||
check ("pow (NaN, +0) == 1", FUNC(pow) (nan_value, 0), 1);
|
||||
check ("pow (NaN, -0) == 1", FUNC(pow) (nan_value, minus_zero), 1);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check_isinfp ("pow (+1.1, +inf) == +inf", FUNC(pow) (1.1, plus_infty));
|
||||
check_isinfp ("pow (+inf, +inf) == +inf", FUNC(pow) (plus_infty, plus_infty));
|
||||
check_isinfp ("pow (-1.1, +inf) == +inf", FUNC(pow) (-1.1, plus_infty));
|
||||
@ -1408,14 +1544,19 @@ pow_test (void)
|
||||
FUNC(pow) (minus_zero, -2), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
check_isinfp_exc ("pow (-0, -11.1) == +inf plus divide-by-zero exception",
|
||||
FUNC(pow) (minus_zero, -11.1), DIVIDE_BY_ZERO_EXCEPTION);
|
||||
#endif
|
||||
|
||||
check ("pow (+0, 1) == +0", FUNC(pow) (0, 1), 0);
|
||||
check ("pow (+0, 11) == +0", FUNC(pow) (0, 11), 0);
|
||||
#ifndef TEST_INLINE
|
||||
check ("pow (-0, 1) == -0", FUNC(pow) (minus_zero, 1), minus_zero);
|
||||
check ("pow (-0, 11) == -0", FUNC(pow) (minus_zero, 11), minus_zero);
|
||||
#endif
|
||||
|
||||
check ("pow (+0, 2) == +0", FUNC(pow) (0, 2), 0);
|
||||
check ("pow (+0, 11.1) == +0", FUNC(pow) (0, 11.1), 0);
|
||||
|
||||
#ifndef TEST_INLINE
|
||||
check ("pow (-0, 2) == +0", FUNC(pow) (minus_zero, 2), 0);
|
||||
check ("pow (-0, 11.1) == +0", FUNC(pow) (minus_zero, 11.1), 0);
|
||||
|
||||
@ -1425,11 +1566,11 @@ pow_test (void)
|
||||
|
||||
x = random_value (-1.0, 1.0);
|
||||
check_ext ("pow (x, +inf) == +0 for |x| < 1",
|
||||
FUNC(pow) (x, plus_infty), 0.0, x);
|
||||
FUNC(pow) (x, plus_infty), 0.0, x);
|
||||
|
||||
x = random_greater (1.0);
|
||||
check_ext ("pow (x, -inf) == +0 for |x| > 1",
|
||||
FUNC(pow) (x, minus_infty), 0.0, x);
|
||||
FUNC(pow) (x, minus_infty), 0.0, x);
|
||||
|
||||
x = random_value (-1.0, 1.0);
|
||||
check_isinfp_ext ("pow (x, -inf) == +inf for |x| < 1",
|
||||
@ -1458,13 +1599,16 @@ pow_test (void)
|
||||
x = ((rand () % 1000000) + 1) * -2.0; /* Get random even integer < 0 */
|
||||
check_ext ("pow (-inf, y) == +0 for y < 0 and not an odd integer",
|
||||
FUNC(pow) (minus_infty, x), 0.0, x);
|
||||
#endif
|
||||
|
||||
x = (rand () % 1000000) * 2.0 + 1; /* Get random odd integer > 0 */
|
||||
check_ext ("pow (+0, y) == +0 for y an odd integer > 0",
|
||||
FUNC(pow) (0.0, x), 0.0, x);
|
||||
#ifndef TEST_INLINE
|
||||
x = (rand () % 1000000) * 2.0 + 1; /* Get random odd integer > 0 */
|
||||
check_ext ("pow (-0, y) == -0 for y an odd integer > 0",
|
||||
FUNC(pow) (minus_zero, x), minus_zero, x);
|
||||
#endif
|
||||
|
||||
x = ((rand () % 1000000) + 1) * 2.0; /* Get random even integer > 1 */
|
||||
check_ext ("pow (+0, y) == +0 for y > 0 and not an odd integer",
|
||||
@ -1682,6 +1826,7 @@ sqrt_test (void)
|
||||
x = random_value (0, 10000);
|
||||
check_ext ("sqrt (x*x) == x", FUNC(sqrt) (x*x), x, x);
|
||||
check ("sqrt (4) == 2", FUNC(sqrt) (4), 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1741,11 +1886,18 @@ cexp_test (void)
|
||||
check ("real(cexp(-inf - 0i)) = 0", __real__ result, 0);
|
||||
check ("imag(cexp(-inf - 0i)) = -0", __imag__ result, minus_zero);
|
||||
|
||||
|
||||
result = FUNC(cexp) (BUILD_COMPLEX (0.0, plus_infty));
|
||||
check_isnan_exc ("real(cexp(0 + i inf)) = NaN plus invalid exception",
|
||||
__real__ result, INVALID_EXCEPTION);
|
||||
check_isnan ("imag(cexp(0 + i inf)) = NaN plus invalid exception",
|
||||
__imag__ result);
|
||||
|
||||
#if defined __GNUC__ && __GNUC__ <= 2 && __GNUC_MINOR <= 7
|
||||
if (verbose)
|
||||
printf ("The following test for cexp might fail due to a gcc compiler error!\n");
|
||||
#endif
|
||||
|
||||
result = FUNC(cexp) (BUILD_COMPLEX (minus_zero, plus_infty));
|
||||
check_isnan_exc ("real(cexp(-0 + i inf)) = NaN plus invalid exception",
|
||||
__real__ result, INVALID_EXCEPTION);
|
||||
@ -3757,6 +3909,15 @@ static void
|
||||
cpow_test (void)
|
||||
{
|
||||
__complex__ MATHTYPE result;
|
||||
|
||||
result = FUNC (cpow) (BUILD_COMPLEX (1, 0), BUILD_COMPLEX (0, 0));
|
||||
check ("real(cpow (1 + i0), (0 + i0)) = 0", __real__ result, 1);
|
||||
check ("imag(cpow (1 + i0), (0 + i0)) = 0", __imag__ result, 0);
|
||||
|
||||
result = FUNC (cpow) (BUILD_COMPLEX (2, 0), BUILD_COMPLEX (10, 0));
|
||||
check ("real(cpow (2 + i0), (10 + i0)) = 1024", __real__ result, 1024);
|
||||
check ("imag(cpow (2 + i0), (10 + i0)) = 0", __imag__ result, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -3887,6 +4048,7 @@ inverse_func_pair_test (const char *test_name,
|
||||
b = inverse (a);
|
||||
(void) &b;
|
||||
|
||||
output_new_test (test_name);
|
||||
result = check_equal (b, x, epsilon, &difference);
|
||||
output_result (test_name, result,
|
||||
b, x, difference, PRINT, PRINT);
|
||||
@ -3941,6 +4103,7 @@ identities1_test (MATHTYPE x, MATHTYPE epsilon)
|
||||
res3 = res1 * res1 + res2 * res2;
|
||||
(void) &res3;
|
||||
|
||||
output_new_test ("sin^2 + cos^2 == 1");
|
||||
result = check_equal (res3, 1.0, epsilon, &diff);
|
||||
output_result_ext ("sin^2 + cos^2 == 1", result,
|
||||
res3, 1.0, diff, x, PRINT, PRINT);
|
||||
@ -3963,6 +4126,7 @@ identities2_test (MATHTYPE x, MATHTYPE epsilon)
|
||||
res4 = res1 / res2;
|
||||
(void) &res4;
|
||||
|
||||
output_new_test ("sin/cos == tan");
|
||||
result = check_equal (res4, res3, epsilon, &diff);
|
||||
output_result_ext ("sin/cos == tan", result,
|
||||
res4, res3, diff, x, PRINT, PRINT);
|
||||
@ -3983,6 +4147,7 @@ identities3_test (MATHTYPE x, MATHTYPE epsilon)
|
||||
res3 = res2 * res2 - res1 * res1;
|
||||
(void) &res3;
|
||||
|
||||
output_new_test ("cosh^2 - sinh^2 == 1");
|
||||
result = check_equal (res3, 1.0, epsilon, &diff);
|
||||
output_result_ext ("cosh^2 - sinh^2 == 1", result,
|
||||
res3, 1.0, diff, x, PRINT, PRINT);
|
||||
@ -4142,7 +4307,7 @@ parse_options (int argc, char *argv[])
|
||||
if (optarg)
|
||||
verbose = (unsigned int) strtoul (optarg, NULL, 0);
|
||||
else
|
||||
verbose = 3;
|
||||
verbose = 4;
|
||||
break;
|
||||
case 's':
|
||||
verbose = 0;
|
||||
@ -4156,10 +4321,12 @@ parse_options (int argc, char *argv[])
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
parse_options (argc, argv);
|
||||
|
||||
initialize ();
|
||||
printf (TEST_MSG);
|
||||
|
||||
basic_tests ();
|
||||
|
||||
acos_test ();
|
||||
|
33
math/test-idouble.c
Normal file
33
math/test-idouble.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#define FUNC(function) function
|
||||
#define MATHTYPE double
|
||||
#define TEST_MSG "testing double (inline functions)\n"
|
||||
#define MATHCONST(x) x
|
||||
#define CHOOSE(Clongdouble,Cdouble,Cfloat) Cdouble
|
||||
#define PRINTF_EXPR "e"
|
||||
#define TEST_INLINE
|
||||
|
||||
#ifdef __NO_MATH_INLINES
|
||||
# undef __NO_MATH_INLINES
|
||||
#endif
|
||||
|
||||
#include "libm-test.c"
|
32
math/test-ifloat.c
Normal file
32
math/test-ifloat.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#define FUNC(function) function ## f
|
||||
#define MATHTYPE float
|
||||
#define TEST_MSG "testing float (inline functions)\n"
|
||||
#define MATHCONST(x) x
|
||||
#define CHOOSE(Clongdouble,Cdouble,Cfloat) Cfloat
|
||||
#define PRINTF_EXPR "e"
|
||||
#define TEST_INLINE
|
||||
|
||||
#ifdef __NO_MATH_INLINES
|
||||
# undef __NO_MATH_INLINES
|
||||
#endif
|
||||
|
||||
#include "libm-test.c"
|
33
math/test-ildoubl.c
Normal file
33
math/test-ildoubl.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1997.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#define FUNC(function) function##l
|
||||
#define MATHTYPE long double
|
||||
#define TEST_MSG "testing long double (inline functions)\n"
|
||||
#define MATHCONST(x) x##L
|
||||
#define CHOOSE(Clongdouble,Cdouble,Cfloat) Clongdouble
|
||||
#define PRINTF_EXPR "Le"
|
||||
#define TEST_INLINE
|
||||
|
||||
#ifdef __NO_MATH_INLINES
|
||||
# undef __NO_MATH_INLINES
|
||||
#endif
|
||||
|
||||
#include "libm-test.c"
|
@ -191,7 +191,7 @@ compile (char *__instring, char *__expbuf, __const char *__endbuf, int __eof)
|
||||
}
|
||||
|
||||
/* Everything is ok. */
|
||||
RETURN ((char *) (__expr_ptr->buffer + __expr->used));
|
||||
RETURN ((char *) (__expr_ptr->buffer + __expr_ptr->used));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <rpcsvc/nis.h>
|
||||
#include <rpcsvc/nislib.h>
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rpcsvc/nis.h>
|
||||
#include <rpcsvc/nislib.h>
|
||||
|
||||
|
@ -101,8 +101,9 @@ LINE_PARSER
|
||||
/* If we need the host entry in IPv6 form change it now. */
|
||||
if (_res.options & RES_USE_INET6)
|
||||
{
|
||||
char *bufptr = data->linebuffer;
|
||||
size_t buflen = (char *) data + datalen - bufptr;
|
||||
char *bufptr = data->linebuffer;
|
||||
/* This should be size_t */
|
||||
int buflen = (char *) data + datalen - bufptr;
|
||||
map_v4v6_hostent (result, &bufptr, &buflen);
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (isxdigit (name[0]) || name[0] == ':')
|
||||
if ((isxdigit (name[0]) && strchr (name, ':') != NULL)
|
||||
|| name[0] == ':')
|
||||
{
|
||||
const char *cp;
|
||||
char *hostname;
|
||||
@ -238,8 +239,6 @@
|
||||
{
|
||||
if (*--cp == '.')
|
||||
break;
|
||||
if (!strchr (name, ':'))
|
||||
break;
|
||||
|
||||
/* All-IPv6-legal, no dot at the end. Fake up a
|
||||
hostent as if we'd actually done a lookup. */
|
||||
|
@ -51,8 +51,7 @@ LINE_PARSER
|
||||
STRING_FIELD (addr, isspace, 1);
|
||||
|
||||
/* Parse address. */
|
||||
if ((_res.options & RES_USE_INET6)
|
||||
&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
|
||||
if (inet_pton (AF_INET6, p, entdata->host_addr) > 0)
|
||||
{
|
||||
result->h_addrtype = AF_INET6;
|
||||
result->h_length = IN6ADDRSZ;
|
||||
@ -81,14 +80,6 @@ LINE_PARSER
|
||||
entdata->h_addr_ptrs[1] = NULL;
|
||||
result->h_addr_list = entdata->h_addr_ptrs;
|
||||
|
||||
/* If we need the host entry in IPv6 form change it now. */
|
||||
if (_res.options & RES_USE_INET6)
|
||||
{
|
||||
char *bufptr = data->linebuffer;
|
||||
int buflen = (char *) data + datalen - bufptr;
|
||||
map_v4v6_hostent (result, &bufptr, &buflen);
|
||||
}
|
||||
|
||||
STRING_FIELD (result->h_name, isspace, 1);
|
||||
})
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
@ -1 +1 @@
|
||||
BIND-4.9.5-P1
|
||||
BIND-4.9.6-T1A
|
||||
|
@ -281,7 +281,12 @@ b64_pton(src, target, targsize)
|
||||
|
||||
case 2: /* Valid, means one byte of info */
|
||||
/* Skip any number of spaces. */
|
||||
#ifdef _LIBC
|
||||
/* To avoid warnings. */
|
||||
for ( ; ch != '\0'; ch = *src++)
|
||||
#else
|
||||
for (NULL; ch != '\0'; ch = *src++)
|
||||
#endif
|
||||
if (!isspace(ch))
|
||||
break;
|
||||
/* Make sure there is another trailing = sign. */
|
||||
@ -296,7 +301,12 @@ b64_pton(src, target, targsize)
|
||||
* We know this char is an =. Is there anything but
|
||||
* whitespace after it?
|
||||
*/
|
||||
#ifdef _LIBC
|
||||
/* To avoid warnings. */
|
||||
for ( ; ch != '\0'; ch = *src++)
|
||||
#else
|
||||
for (NULL; ch != '\0'; ch = *src++)
|
||||
#endif
|
||||
if (!isspace(ch))
|
||||
return (-1);
|
||||
|
||||
|
@ -212,6 +212,10 @@ getanswer(answer, anslen, qname, qtype)
|
||||
* (i.e., with the succeeding search-domain tacked on).
|
||||
*/
|
||||
n = strlen(bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN) {
|
||||
__set_h_errno (NO_RECOVERY);
|
||||
return (NULL);
|
||||
}
|
||||
host.h_name = bp;
|
||||
bp += n;
|
||||
buflen -= n;
|
||||
@ -256,11 +260,15 @@ getanswer(answer, anslen, qname, qtype)
|
||||
/* Store alias. */
|
||||
*ap++ = bp;
|
||||
n = strlen(bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
bp += n;
|
||||
buflen -= n;
|
||||
/* Get canonical name. */
|
||||
n = strlen(tbuf) + 1; /* for the \0 */
|
||||
if (n > buflen) {
|
||||
if (n > buflen || n >= MAXHOSTNAMELEN) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
@ -272,14 +280,14 @@ getanswer(answer, anslen, qname, qtype)
|
||||
}
|
||||
if (qtype == T_PTR && type == T_CNAME) {
|
||||
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
|
||||
if ((n < 0) || !res_hnok(tbuf)) {
|
||||
if (n < 0 || !res_hnok(tbuf)) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
cp += n;
|
||||
/* Get canonical name. */
|
||||
n = strlen(tbuf) + 1; /* for the \0 */
|
||||
if (n > buflen) {
|
||||
if (n > buflen || n >= MAXHOSTNAMELEN) {
|
||||
had_error++;
|
||||
continue;
|
||||
}
|
||||
@ -320,6 +328,10 @@ getanswer(answer, anslen, qname, qtype)
|
||||
n = -1;
|
||||
if (n != -1) {
|
||||
n = strlen(bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN) {
|
||||
had_error++;
|
||||
break;
|
||||
}
|
||||
bp += n;
|
||||
buflen -= n;
|
||||
}
|
||||
@ -328,6 +340,10 @@ getanswer(answer, anslen, qname, qtype)
|
||||
host.h_name = bp;
|
||||
if (_res.options & RES_USE_INET6) {
|
||||
n = strlen(bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN) {
|
||||
had_error++;
|
||||
break;
|
||||
}
|
||||
bp += n;
|
||||
buflen -= n;
|
||||
map_v4v6_hostent(&host, &bp, &buflen);
|
||||
@ -395,8 +411,8 @@ getanswer(answer, anslen, qname, qtype)
|
||||
# endif /*RESOLVSORT*/
|
||||
if (!host.h_name) {
|
||||
n = strlen(qname) + 1; /* for the \0 */
|
||||
if (n > buflen)
|
||||
goto try_again;
|
||||
if (n > buflen || n >= MAXHOSTNAMELEN)
|
||||
goto no_recovery;
|
||||
strcpy(bp, qname);
|
||||
host.h_name = bp;
|
||||
bp += n;
|
||||
@ -407,8 +423,8 @@ getanswer(answer, anslen, qname, qtype)
|
||||
__set_h_errno (NETDB_SUCCESS);
|
||||
return (&host);
|
||||
}
|
||||
try_again:
|
||||
__set_h_errno (TRY_AGAIN);
|
||||
no_recovery:
|
||||
__set_h_errno (NO_RECOVERY);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@ -508,13 +524,12 @@ gethostbyname2(name, af)
|
||||
if (!isdigit(*cp) && *cp != '.')
|
||||
break;
|
||||
}
|
||||
if (isxdigit(name[0]) || name[0] == ':')
|
||||
if ((isxdigit(name[0]) && strchr(name, ':') != NULL) ||
|
||||
name[0] == ':')
|
||||
for (cp = name;; ++cp) {
|
||||
if (!*cp) {
|
||||
if (*--cp == '.')
|
||||
break;
|
||||
if (!strchr(name, ':'))
|
||||
break;
|
||||
/*
|
||||
* All-IPv6-legal, no dot at the end.
|
||||
* Fake up a hostent as if we'd actually
|
||||
@ -719,8 +734,7 @@ _gethtent()
|
||||
if (!(cp = strpbrk(p, " \t")))
|
||||
goto again;
|
||||
*cp++ = '\0';
|
||||
if ((_res.options & RES_USE_INET6) &&
|
||||
inet_pton(AF_INET6, p, host_addr) > 0) {
|
||||
if (inet_pton(AF_INET6, p, host_addr) > 0) {
|
||||
af = AF_INET6;
|
||||
len = IN6ADDRSZ;
|
||||
} else if (inet_pton(AF_INET, p, host_addr) > 0) {
|
||||
@ -757,12 +771,6 @@ _gethtent()
|
||||
*cp++ = '\0';
|
||||
}
|
||||
*q = NULL;
|
||||
if (_res.options & RES_USE_INET6) {
|
||||
char *bp = hostbuf;
|
||||
int buflen = sizeof hostbuf;
|
||||
|
||||
map_v4v6_hostent(&host, &bp, &buflen);
|
||||
}
|
||||
__set_h_errno (NETDB_SUCCESS);
|
||||
return (&host);
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ inet_net_pton_ipv4(src, dst, size)
|
||||
goto emsgsize;
|
||||
}
|
||||
|
||||
/* Fiery death and destruction unless we prefetched EOS. */
|
||||
/* Firey death and destruction unless we prefetched EOS. */
|
||||
if (ch != '\0')
|
||||
goto enoent;
|
||||
|
||||
|
@ -342,6 +342,11 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
* (i.e., with the succeeding search-domain tacked on).
|
||||
*/
|
||||
n = strlen (bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
__set_h_errno (NO_RECOVERY);
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
result->h_name = bp;
|
||||
bp += n;
|
||||
linebuflen -= n;
|
||||
@ -396,11 +401,16 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
/* Store alias. */
|
||||
*ap++ = bp;
|
||||
n = strlen (bp) + 1; /* For the \0. */
|
||||
if (n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
}
|
||||
bp += n;
|
||||
linebuflen -= n;
|
||||
/* Get canonical name. */
|
||||
n = strlen (tbuf) + 1; /* For the \0. */
|
||||
if ((size_t) n > buflen)
|
||||
if ((size_t) n > buflen || n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
@ -423,7 +433,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
cp += n;
|
||||
/* Get canonical name. */
|
||||
n = strlen (tbuf) + 1; /* For the \0. */
|
||||
if ((size_t) n > buflen)
|
||||
if ((size_t) n > buflen || n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
++had_error;
|
||||
continue;
|
||||
@ -469,6 +479,11 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
if (n != -1)
|
||||
{
|
||||
n = strlen (bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
++had_error;
|
||||
break;
|
||||
}
|
||||
bp += n;
|
||||
linebuflen -= n;
|
||||
}
|
||||
@ -478,6 +493,11 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
if (_res.options & RES_USE_INET6)
|
||||
{
|
||||
n = strlen (bp) + 1; /* for the \0 */
|
||||
if (n >= MAXHOSTNAMELEN)
|
||||
{
|
||||
++had_error;
|
||||
break;
|
||||
}
|
||||
bp += n;
|
||||
linebuflen -= n;
|
||||
map_v4v6_hostent (result, &bp, &linebuflen);
|
||||
@ -549,8 +569,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
if (result->h_name == NULL)
|
||||
{
|
||||
n = strlen (qname) + 1; /* For the \0. */
|
||||
if (n > linebuflen)
|
||||
goto try_again;
|
||||
if (n > linebuflen || n >= MAXHOSTNAMELEN)
|
||||
goto no_recovery;
|
||||
strcpy (bp, qname); /* Cannot overflow. */
|
||||
result->h_name = bp;
|
||||
bp += n;
|
||||
@ -562,7 +582,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
*h_errnop = NETDB_SUCCESS;
|
||||
return NSS_STATUS_SUCCESS;
|
||||
}
|
||||
try_again:
|
||||
*h_errnop = TRY_AGAIN;
|
||||
no_recovery:
|
||||
*h_errnop = NO_RECOVERY;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ dn_expand(msg, eomorig, comp_dn, exp_dn, length)
|
||||
register char *dn;
|
||||
register int n, c;
|
||||
char *eom;
|
||||
int len = -1, checked = 0;
|
||||
int len = -1, checked = 0, octets = 0;
|
||||
|
||||
dn = exp_dn;
|
||||
cp = comp_dn;
|
||||
@ -108,6 +108,9 @@ dn_expand(msg, eomorig, comp_dn, exp_dn, length)
|
||||
*/
|
||||
switch (n & INDIR_MASK) {
|
||||
case 0:
|
||||
octets += (n + 1);
|
||||
if (octets > MAXCDNAME)
|
||||
return (-1);
|
||||
if (dn != exp_dn) {
|
||||
if (dn >= eom)
|
||||
return (-1);
|
||||
@ -179,6 +182,8 @@ dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
|
||||
|
||||
dn = (u_char *)exp_dn;
|
||||
cp = comp_dn;
|
||||
if (length > MAXCDNAME)
|
||||
length = MAXCDNAME;
|
||||
eob = cp + length;
|
||||
lpp = cpp = NULL;
|
||||
if (dnptrs != NULL) {
|
||||
|
@ -1146,40 +1146,47 @@ static u_int8_t
|
||||
precsize_aton(strptr)
|
||||
char **strptr;
|
||||
{
|
||||
unsigned int mval = 0, cmval = 0;
|
||||
u_int8_t retval = 0;
|
||||
register char *cp;
|
||||
register int exponent;
|
||||
register int mantissa;
|
||||
char *cp;
|
||||
int exponent = 0;
|
||||
int mantissa = 0;
|
||||
|
||||
cp = *strptr;
|
||||
while (isdigit(*cp)) {
|
||||
if (mantissa == 0)
|
||||
mantissa = *cp - '0';
|
||||
else
|
||||
exponent++;
|
||||
cp++;
|
||||
}
|
||||
|
||||
while (isdigit(*cp))
|
||||
mval = mval * 10 + (*cp++ - '0');
|
||||
|
||||
if (*cp == '.') { /* centimeters */
|
||||
if (*cp == '.') {
|
||||
cp++;
|
||||
if (isdigit(*cp)) {
|
||||
cmval = (*cp++ - '0') * 10;
|
||||
if (mantissa == 0)
|
||||
mantissa = *cp - '0';
|
||||
else
|
||||
exponent++;
|
||||
cp++;
|
||||
|
||||
if (isdigit(*cp)) {
|
||||
cmval += (*cp++ - '0');
|
||||
if (mantissa == 0)
|
||||
mantissa = *cp - '0';
|
||||
else
|
||||
exponent++;
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
exponent++;
|
||||
}
|
||||
}
|
||||
cmval = (mval * 100) + cmval;
|
||||
|
||||
for (exponent = 0; exponent < 9; exponent++)
|
||||
if (cmval < poweroften[exponent+1])
|
||||
break;
|
||||
|
||||
mantissa = cmval / poweroften[exponent];
|
||||
if (mantissa > 9)
|
||||
mantissa = 9;
|
||||
else
|
||||
exponent += 2;
|
||||
|
||||
if (mantissa == 0)
|
||||
exponent = 0;
|
||||
retval = (mantissa << 4) | exponent;
|
||||
|
||||
*strptr = cp;
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ res_init()
|
||||
register FILE *fp;
|
||||
register char *cp, **pp;
|
||||
register int n;
|
||||
char buf[BUFSIZ];
|
||||
char buf[MAXDNAME];
|
||||
int nserv = 0; /* number of nameserver records read from file */
|
||||
int haveenv = 0;
|
||||
int havesearch = 0;
|
||||
|
@ -601,6 +601,11 @@ read_len:
|
||||
if ((long) timeout.tv_sec <= 0)
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
if (s+1 > FD_SETSIZE) {
|
||||
Perror(stderr, "s+1 > FD_SETSIZE", EMFILE);
|
||||
res_close();
|
||||
goto next_ns;
|
||||
}
|
||||
wait:
|
||||
FD_ZERO(&dsmask);
|
||||
FD_SET(s, &dsmask);
|
||||
|
@ -6,8 +6,7 @@
|
||||
int win = 0;
|
||||
|
||||
void
|
||||
handler (sig)
|
||||
int sig;
|
||||
handler (int sig)
|
||||
{
|
||||
printf ("Received signal %d (%s).\n", sig, strsignal(sig));
|
||||
win = 1;
|
||||
|
@ -3,8 +3,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
compare (a, b)
|
||||
const char *a, *b;
|
||||
compare (const char *a, const char *b)
|
||||
{
|
||||
return strcmp (*(char **) a, *(char **) b);
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ size_t errors = 0;
|
||||
|
||||
/* Complain if condition is not true. */
|
||||
void
|
||||
check (thing, number)
|
||||
int thing, number;
|
||||
check (int thing, int number)
|
||||
{
|
||||
if (!thing)
|
||||
{
|
||||
@ -40,9 +39,7 @@ char one[50];
|
||||
char two[50];
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
main (void)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
|
@ -155,6 +155,10 @@ struct svc_req {
|
||||
SVCXPRT *rq_xprt; /* associated transport */
|
||||
};
|
||||
|
||||
#ifndef __DISPATCH_FN_T
|
||||
#define __DISPATCH_FN_T
|
||||
typedef void (*__dispatch_fn_t) __P((struct svc_req*, SVCXPRT*));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Service registration
|
||||
@ -167,8 +171,7 @@ struct svc_req {
|
||||
* u_long protocol; like TCP or UDP, zero means do not register
|
||||
*/
|
||||
extern bool_t svc_register __P ((SVCXPRT *__xprt, u_long __prog,
|
||||
u_long __vers, void (*__dispatch)
|
||||
__P ((struct svc_req *, SVCXPRT *)),
|
||||
u_long __vers, __dispatch_fn_t __dispatch,
|
||||
u_long __protocol));
|
||||
|
||||
/*
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
/* Set N bytes of S to 0. */
|
||||
void
|
||||
bzero (s, n)
|
||||
bzero (s, len)
|
||||
void *s;
|
||||
size_t len;
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <stddef.h> /* For size_t and NULL. */
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy no more than N bytes of SRC to DEST, stopping when C is found.
|
||||
|
@ -29,9 +29,7 @@
|
||||
/* If VT is not NULL, write statistics for WHO into *VT.
|
||||
Return 0 for success, -1 for failure. */
|
||||
static int
|
||||
vtimes_one (vt, who)
|
||||
struct vtimes *vt;
|
||||
enum __rusage_who who;
|
||||
vtimes_one (struct vtimes *vt, enum __rusage_who who)
|
||||
{
|
||||
if (vt != NULL)
|
||||
{
|
||||
|
@ -35,55 +35,42 @@ float_type
|
||||
s(__ieee754_atan2) (float_type y, float_type x)
|
||||
{
|
||||
float_type pi, pi_2, z;
|
||||
unsigned long y_cond, x_cond;
|
||||
|
||||
__asm ("fmovecr%.x %#0, %0" : "=f" (pi));
|
||||
__asm ("fscale%.w %#-1, %0" : "=f" (pi_2) : "0" (pi));
|
||||
if (x != x || y != y)
|
||||
y_cond = __m81_test (y);
|
||||
x_cond = __m81_test (x);
|
||||
|
||||
if ((x_cond | y_cond) & __M81_COND_NAN)
|
||||
z = x + y;
|
||||
else if (y == 0)
|
||||
else if (y_cond & __M81_COND_ZERO)
|
||||
{
|
||||
if (m81(__signbit) (x))
|
||||
z = m81(__signbit) (y) ? -pi : pi;
|
||||
if (x_cond & __M81_COND_NEG)
|
||||
z = y_cond & __M81_COND_NEG ? -pi : pi;
|
||||
else
|
||||
z = y;
|
||||
}
|
||||
else if (m81(__isinf) (x))
|
||||
else if (x_cond & __M81_COND_INF)
|
||||
{
|
||||
if (m81(__isinf) (y))
|
||||
if (y_cond & __M81_COND_INF)
|
||||
{
|
||||
float_type pi_4;
|
||||
__asm ("fscale%.w %#-2, %0" : "=f" (pi_4) : "0" (pi));
|
||||
z = x > 0 ? pi_4 : 3 * pi_4;
|
||||
z = x_cond & __M81_COND_NEG ? 3 * pi_4 : pi_4;
|
||||
}
|
||||
else
|
||||
z = x > 0 ? 0 : pi;
|
||||
if (m81(__signbit) (y))
|
||||
z = x_cond & __M81_COND_NEG ? pi : 0;
|
||||
if (y_cond & __M81_COND_NEG)
|
||||
z = -z;
|
||||
}
|
||||
else if (m81(__isinf) (y))
|
||||
z = y > 0 ? pi_2 : -pi_2;
|
||||
else if (x > 0)
|
||||
else if (y_cond & __M81_COND_INF)
|
||||
z = y_cond & __M81_COND_NEG ? -pi_2 : pi_2;
|
||||
else if (x_cond & __M81_COND_NEG)
|
||||
{
|
||||
if (y > 0)
|
||||
if (y_cond & __M81_COND_NEG)
|
||||
{
|
||||
if (x > y)
|
||||
z = m81(__atan) (y / x);
|
||||
else
|
||||
z = pi_2 - m81(__atan) (x / y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > -y)
|
||||
z = m81(__atan) (y / x);
|
||||
else
|
||||
z = -pi_2 - m81(__atan) (x / y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y < 0)
|
||||
{
|
||||
if (-x > y)
|
||||
if (-x > -y)
|
||||
z = -pi + m81(__atan) (y / x);
|
||||
else
|
||||
z = -pi_2 - m81(__atan) (x / y);
|
||||
@ -96,5 +83,22 @@ s(__ieee754_atan2) (float_type y, float_type x)
|
||||
z = pi_2 - m81(__atan) (x / y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y_cond & __M81_COND_NEG)
|
||||
{
|
||||
if (x > -y)
|
||||
z = m81(__atan) (y / x);
|
||||
else
|
||||
z = -pi_2 - m81(__atan) (x / y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x > y)
|
||||
z = m81(__atan) (y / x);
|
||||
else
|
||||
z = pi_2 - m81(__atan) (x / y);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ $(common-objpfx)ioctls: $(sysdep_dir)/unix/snarf-ioctls \
|
||||
$(sysincludedir)/sys/ioctl.h $(ioctl-includes)
|
||||
$(dir $<)$(notdir $<) $(filter-out $<,$^) \
|
||||
| fgrep -xv "`($(dir $<)$(notdir $<) $(termbits.h) \
|
||||
$(..)termios/sys/ttydefaults.h; \
|
||||
$(..)sysdeps/generic/sys/ttydefaults.h; \
|
||||
echo NULL) \
|
||||
| sort | uniq`" \
|
||||
| sort | uniq | tr '\012' ' ' > $@-tmp
|
||||
|
@ -17,6 +17,7 @@
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Set an alarm to go off (generating a SIGALRM signal) in VALUE microseconds.
|
||||
If INTERVAL is nonzero, when the alarm goes off, the timer is reset to go
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef _NET_PPP_DEFS_H
|
||||
#define _NET_PPP_DEFS_H 1
|
||||
|
||||
#define __need_time_t
|
||||
#include <time.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <linux/ppp_defs.h>
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <net/if.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -62,10 +62,10 @@ typedef int int_least32_t;
|
||||
typedef long long int int_least64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef unsigned char int_least8_t;
|
||||
typedef unsigned short int int_least16_t;
|
||||
typedef unsigned int int_least32_t;
|
||||
typedef unsigned long long int int_least64_t;
|
||||
typedef unsigned char uint_least8_t;
|
||||
typedef unsigned short int uint_least16_t;
|
||||
typedef unsigned int uint_least32_t;
|
||||
typedef unsigned long long int uint_least64_t;
|
||||
|
||||
|
||||
/* Fast types. */
|
||||
@ -77,10 +77,10 @@ typedef int int_fast32_t;
|
||||
typedef long long int int_fast64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef unsigned char int_fast8_t;
|
||||
typedef unsigned int int_fast16_t;
|
||||
typedef unsigned int int_fast32_t;
|
||||
typedef unsigned long long int int_fast64_t;
|
||||
typedef unsigned char uint_fast8_t;
|
||||
typedef unsigned int uint_fast16_t;
|
||||
typedef unsigned int uint_fast32_t;
|
||||
typedef unsigned long long int uint_fast64_t;
|
||||
|
||||
|
||||
/* Limits of integral types. */
|
||||
@ -122,21 +122,21 @@ typedef unsigned long long int int_fast64_t;
|
||||
|
||||
|
||||
/* Minimum of fast signed integral types having a minimum size. */
|
||||
#define INT_LEAST8_MIN (-128)
|
||||
#define INT_LEAST16_MIN (-2147483647-1)
|
||||
#define INT_LEAST32_MIN (-2147483647-1)
|
||||
#define INT_LEAST64_MIN (-9223372036854775807LL-1)
|
||||
#define INT_FAST8_MIN (-128)
|
||||
#define INT_FAST16_MIN (-2147483647-1)
|
||||
#define INT_FAST32_MIN (-2147483647-1)
|
||||
#define INT_FAST64_MIN (-9223372036854775807LL-1)
|
||||
/* Maximum of fast signed integral types having a minimum size. */
|
||||
#define INT_LEAST8_MAX (127)
|
||||
#define INT_LEAST16_MAX (2147483647)
|
||||
#define INT_LEAST32_MAX (2147483647)
|
||||
#define INT_LEAST64_MAX (9223372036854775807LL)
|
||||
#define INT_FAST8_MAX (127)
|
||||
#define INT_FAST16_MAX (2147483647)
|
||||
#define INT_FAST32_MAX (2147483647)
|
||||
#define INT_FAST64_MAX (9223372036854775807LL)
|
||||
|
||||
/* Maximum of fast unsigned integral types having a minimum size. */
|
||||
#define UINT_LEAST8_MAX (255U)
|
||||
#define UINT_LEAST16_MAX (4294967295U)
|
||||
#define UINT_LEAST32_MAX (4294967295U)
|
||||
#define UINT_LEAST64_MAX (18446744073709551615uLL)
|
||||
#define UINT_FAST8_MAX (255U)
|
||||
#define UINT_FAST16_MAX (4294967295U)
|
||||
#define UINT_FAST32_MAX (4294967295U)
|
||||
#define UINT_FAST64_MAX (18446744073709551615uLL)
|
||||
|
||||
|
||||
/* Minimum for most efficient signed integral types. */
|
||||
|
@ -62,10 +62,10 @@ typedef int int_least32_t;
|
||||
typedef long int int_least64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef unsigned char int_least8_t;
|
||||
typedef unsigned short int int_least16_t;
|
||||
typedef unsigned int int_least32_t;
|
||||
typedef unsigned long int int_least64_t;
|
||||
typedef unsigned char uint_least8_t;
|
||||
typedef unsigned short int uint_least16_t;
|
||||
typedef unsigned int uint_least32_t;
|
||||
typedef unsigned long int uint_least64_t;
|
||||
|
||||
|
||||
/* Fast types. */
|
||||
@ -77,10 +77,10 @@ typedef int int_fast32_t;
|
||||
typedef long int int_fast64_t;
|
||||
|
||||
/* Unsigned. */
|
||||
typedef unsigned char int_fast8_t;
|
||||
typedef unsigned int int_fast16_t;
|
||||
typedef unsigned int int_fast32_t;
|
||||
typedef unsigned long int int_fast64_t;
|
||||
typedef unsigned char uint_fast8_t;
|
||||
typedef unsigned int uint_fast16_t;
|
||||
typedef unsigned int uint_fast32_t;
|
||||
typedef unsigned long int uint_fast64_t;
|
||||
|
||||
|
||||
/* Limits of integral types. */
|
||||
@ -122,21 +122,21 @@ typedef unsigned long int int_fast64_t;
|
||||
|
||||
|
||||
/* Minimum of fast signed integral types having a minimum size. */
|
||||
#define INT_LEAST8_MIN (-128)
|
||||
#define INT_LEAST16_MIN (-2147483647-1)
|
||||
#define INT_LEAST32_MIN (-2147483647-1)
|
||||
#define INT_LEAST64_MIN (-9223372036854775807L-1)
|
||||
#define INT_FAST8_MIN (-128)
|
||||
#define INT_FAST16_MIN (-2147483647-1)
|
||||
#define INT_FAST32_MIN (-2147483647-1)
|
||||
#define INT_FAST64_MIN (-9223372036854775807L-1)
|
||||
/* Maximum of fast signed integral types having a minimum size. */
|
||||
#define INT_LEAST8_MAX (127)
|
||||
#define INT_LEAST16_MAX (2147483647)
|
||||
#define INT_LEAST32_MAX (2147483647)
|
||||
#define INT_LEAST64_MAX (9223372036854775807L)
|
||||
#define INT_FAST8_MAX (127)
|
||||
#define INT_FAST16_MAX (2147483647)
|
||||
#define INT_FAST32_MAX (2147483647)
|
||||
#define INT_FAST64_MAX (9223372036854775807L)
|
||||
|
||||
/* Maximum of fast unsigned integral types having a minimum size. */
|
||||
#define UINT_LEAST8_MAX (255U)
|
||||
#define UINT_LEAST16_MAX (4294967295U)
|
||||
#define UINT_LEAST32_MAX (4294967295U)
|
||||
#define UINT_LEAST64_MAX (18446744073709551615uL)
|
||||
#define UINT_FAST8_MAX (255U)
|
||||
#define UINT_FAST16_MAX (4294967295U)
|
||||
#define UINT_FAST32_MAX (4294967295U)
|
||||
#define UINT_FAST64_MAX (18446744073709551615uL)
|
||||
|
||||
|
||||
/* Minimum for most efficient signed integral types. */
|
||||
|
@ -137,7 +137,7 @@ extern int __tz_compute __P ((time_t timer, const struct tm *tm));
|
||||
# if ! HAVE_LOCALTIME_R
|
||||
# if ! HAVE_TM_GMTOFF
|
||||
/* Approximate gmtime_r as best we can in its absence. */
|
||||
# define gmtime_r my_gmtime_r
|
||||
# define gmtime_r my_gmtime_r
|
||||
static struct tm *gmtime_r __P ((const time_t *, struct tm *));
|
||||
static struct tm *
|
||||
gmtime_r (t, tp)
|
||||
@ -208,7 +208,7 @@ static const char zeroes[16] = "0000000000000000";
|
||||
# define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
|
||||
#endif
|
||||
|
||||
#define add(n, f) \
|
||||
#define add(n, f) \
|
||||
do \
|
||||
{ \
|
||||
int _n = (n); \
|
||||
@ -231,7 +231,7 @@ static const char zeroes[16] = "0000000000000000";
|
||||
i += _incr; \
|
||||
} while (0)
|
||||
|
||||
#define cpy(n, s) \
|
||||
#define cpy(n, s) \
|
||||
add ((n), \
|
||||
if (to_lowcase) \
|
||||
memcpy_lowcase (p, (s), _n); \
|
||||
|
@ -541,7 +541,10 @@ strptime_internal (buf, format, tm, decided)
|
||||
break;
|
||||
case 'Y':
|
||||
/* Match year including century number. */
|
||||
get_number (0, INT_MAX);
|
||||
if (sizeof (time_t) > 4)
|
||||
get_number (0, 9999);
|
||||
else
|
||||
get_number (0, 2036);
|
||||
tm->tm_year = val - 1900;
|
||||
break;
|
||||
case 'Z':
|
||||
|
Loading…
x
Reference in New Issue
Block a user