diff options
72 files changed, 4263 insertions, 677 deletions
@@ -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 @@ -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. diff --git a/argp/argp-help.c b/argp/argp-help.c index e18ee418f5..2120ab1526 100644 --- a/argp/argp-help.c +++ b/argp/argp-help.c @@ -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) { diff --git a/argp/argp.h b/argp/argp.h index 886742a36e..61ed8351e6 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -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 diff --git a/db/hash/extern.h b/db/hash/extern.h index 3167e6d0f7..4f1f23d67c 100644 --- a/db/hash/extern.h +++ b/db/hash/extern.h @@ -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)); diff --git a/db/hash/hash.c b/db/hash/hash.c index db6fd69a4b..08f2a7e3c8 100644 --- a/db/hash/hash.c +++ b/db/hash/hash.c @@ -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; diff --git a/db/hash/hash.h b/db/hash/hash.h index 62176d7b1f..d07db6f071 100644 --- a/db/hash/hash.h +++ b/db/hash/hash.h @@ -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)); diff --git a/db/hash/hash_log2.c b/db/hash/hash_log2.c index 92fda72ff0..6bcf9c1145 100644 --- a/db/hash/hash_log2.c +++ b/db/hash/hash_log2.c @@ -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; diff --git a/inet/netinet/icmp6.h b/inet/netinet/icmp6.h index ef85269117..90c61afda8 100644 --- a/inet/netinet/icmp6.h +++ b/inet/netinet/icmp6.h @@ -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)); @@ -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 +struct dir_data +{ + DIR *stream; + char *content; +}; -/* 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 ftw_data { - int got; - struct dirent *entry; + struct dir_data **dirstreams; + size_t actdir; + size_t maxdir; - got = 0; + char *dirbuf; + size_t dirbufsize; + struct FTW ftw; - __set_errno (0); + int flags; - while ((entry = readdir (dirs[level])) != NULL) - { - struct stat s; - int flag, retval, newlev; - size_t namlen; + int *cvt_arr; + __nftw_func_t func; - ++got; + struct stat st; - if (entry->d_name[0] == '.' - && (entry->d_name[1] == '\0' || - (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) - { - __set_errno (0); - continue; - } + dev_t dev; +}; - namlen = _D_EXACT_NAMLEN (entry); - if (namlen + len + 1 > PATH_MAX) - { -#ifdef ENAMETOOLONG - __set_errno (ENAMETOOLONG); -#else - __set_errno (ENOMEM); -#endif - return -1; - } +/* 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 +}; - dir[len] = '/'; - memcpy ((void *) (dir + len + 1), (void *) entry->d_name, - namlen + 1); +static int ftw_arr[] = +{ + FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS +}; - if (stat (dir, &s) < 0) - { - if (errno != EACCES && errno != ENOENT) - return -1; - flag = FTW_NS; - } - else if (S_ISDIR (s.st_mode)) + +/* 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) + { + /* 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); + + if (buf == NULL) + result = -1; + else { - newlev = (level + 1) % descriptors; + DIR *st = data->dirstreams[data->actdir]->stream; + struct dirent *d; + size_t actsize = 0; + + 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; + } + + memcpy (buf + actsize, d->d_name, this_len); + actsize += this_len; + buf[actsize++] = '\0'; + } - if (dirs[newlev] != NULL) - closedir (dirs[newlev]); + /* Terminate the list with an additional NUL byte. */ + buf[actsize++] = '\0'; - 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; } } + } + + /* 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 - flag = FTW_F; + { + dirp->content = NULL; + data->dirstreams[data->actdir] = dirp; + + if (++data->actdir == data->maxdir) + data->actdir = 0; + } + } + + return result; +} + + +static inline int +process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, + size_t namlen) +{ + int result = 0; + int flag; + + if (name[0] == '.' && (name[1] == '\0' + || (name[1] == '.' && name[2] == '\0'))) + /* Don't process the "." and ".." entries. */ + return 0; + + if (data->dirbufsize < data->ftw.base + namlen + 2) + { + /* Enlarge the buffer. */ + char *newp; + + data->dirbufsize *= 2; + newp = realloc (data->dirbuf, data->dirbufsize); + if (newp == NULL) + return -1; + data->dirbuf = newp; + } - retval = (*func) (dir, &s, flag); + 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) + result = -1; + else if (!(data->flags & FTW_PHYS) + && lstat (data->dirbuf, &data->st) == 0 + && S_ISLNK (data->st.st_mode)) + flag = FTW_SLN; + else + flag = FTW_NS; + } + else + { + 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; + } + + if (result == 0 + && (!(data->flags & FTW_MOUNT) || data->st.st_dev == data->dev)) + { if (flag == FTW_D) { - if (retval == 0) - retval = ftw_dir (dirs, newlev, descriptors, dir, - namlen + len + 1, func); - if (dirs[newlev] != NULL) - { - int save; + result = ftw_dir (data); - save = errno; - closedir (dirs[newlev]); - __set_errno (save); - dirs[newlev] = NULL; + 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; + } - if (retval != 0) - return retval; + /* 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 (dirs[level] == NULL) + /* If necessary, change to this directory. */ + if (data->flags & FTW_CHDIR) + { + if (fchdir (dirfd (dir.stream)) < 0) { - int skip; - - dir[len] = '\0'; - dirs[level] = opendir (dir); - if (dirs[level] == NULL) - return -1; - skip = got; - while (skip-- != 0) + if (errno == ENOSYS) { - __set_errno (0); - if (readdir (dirs[level]) == NULL) - return errno == 0 ? 0 : -1; + if (chdir (data->dirbuf) < 0) + result = -1; } + else + result = -1; } - __set_errno (0); + 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 errno == 0 ? 0 : -1; -} + /* Next, update the `struct FTW' information. */ + ++data->ftw.level; + startp = strchr (data->dirbuf, '\0'); + *startp++ = '/'; + data->ftw.base = startp - data->dirbuf; -/* Call a function on every element in a directory tree. */ + 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; + } -int -ftw (const char *dir, - int (*func) (const char *file, const struct stat *status, int flag), - int descriptors) -{ - DIR **dirs; - size_t len; - char buf[PATH_MAX + 1]; - struct stat s; - int flag, retval; - int i; - - if (descriptors <= 0) - descriptors = 1; - - dirs = (DIR **) __alloca (descriptors * sizeof (DIR *)); - i = descriptors; - while (i-- > 0) - dirs[i] = NULL; - - if (stat (dir, &s) < 0) + if (dir.stream != NULL) { - if (errno != EACCES && errno != ENOENT) - return -1; - flag = FTW_NS; + /* 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 if (S_ISDIR (s.st_mode)) + else { - dirs[0] = opendir (dir); - if (dirs[0] != NULL) - flag = FTW_D; - else + int save_err; + char *runp = dir.content; + + assert (result == 0); + + while (*runp != '\0') { - if (errno != EACCES) - return -1; - flag = FTW_DNR; + 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); } - else - flag = FTW_F; - len = strlen (dir); - memcpy ((void *) buf, (void *) dir, len + 1); + /* 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); - retval = (*func) (buf, &s, flag); + 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; + } - if (flag == FTW_D) + 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) { - if (retval == 0) - retval = ftw_dir (dirs, 0, descriptors, buf, len, func); - if (dirs[0] != NULL) + /* GNU extension ahead. */ + cwd = getcwd (NULL, 0); + if (cwd == NULL) + result = -1; + else { - int save; - - save = errno; - closedir (dirs[0]); - __set_errno (save); + /* 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; + } } } - return retval; + /* 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); } @@ -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 diff --git a/login/Makefile b/login/Makefile index 6c10a5aff4..832b1caf63 100644 --- a/login/Makefile +++ b/login/Makefile @@ -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. diff --git a/login/getutent_r.c b/login/getutent_r.c index 580dcffb21..3cc46da96c 100644 --- a/login/getutent_r.c +++ b/login/getutent_r.c @@ -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) diff --git a/login/login.c b/login/login.c index 7cbe8b603e..6bd0e6eaef 100644 --- a/login/login.c +++ b/login/login.c @@ -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, ©); } diff --git a/login/logwtmp.c b/login/logwtmp.c index b6af813e73..58f07ff1ce 100644 --- a/login/logwtmp.c +++ b/login/logwtmp.c @@ -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); } diff --git a/login/pty.h b/login/pty.h index 09024a787a..731ab12d82 100644 --- a/login/pty.h +++ b/login/pty.h @@ -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> diff --git a/login/updwtmp.c b/login/updwtmp.c new file mode 100644 index 0000000000..9965a61fbb --- /dev/null +++ b/login/updwtmp.c @@ -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); + } +} + diff --git a/login/utmp-private.h b/login/utmp-private.h index 4825ae3f6d..c5e7742a4d 100644 --- a/login/utmp-private.h +++ b/login/utmp-private.h @@ -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 */ + + + diff --git a/login/utmp.h b/login/utmp.h index 9be0ec5b06..799b1a17ac 100644 --- a/login/utmp.h +++ b/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)); diff --git a/login/utmp_daemon.c b/login/utmp_daemon.c new file mode 100644 index 0000000000..edaade1eff --- /dev/null +++ b/login/utmp_daemon.c @@ -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; +} diff --git a/login/utmp_db.c b/login/utmp_db.c deleted file mode 100644 index fa0e29a52e..0000000000 --- a/login/utmp_db.c +++ /dev/null @@ -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; -} diff --git a/login/utmp_file.c b/login/utmp_file.c index 9a5d687291..1366f38d75 100644 --- a/login/utmp_file.c +++ b/login/utmp_file.c @@ -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; + /* This time we ignore the error. */ + __flock (fd, LOCK_EX | LOCK_NB); + } - if (file_name != default_file_name) - free ((char *) file_name); + /* Remember original size of log file. */ + if (__fstat (fd, &st) < 0) + goto fail; - file_name = new_name; - } + /* 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; } - return 0; + + result = 0; + +fail: + /* And unlock the file. */ + __flock (fd, LOCK_UN); + + /* Close WTMP file. */ + __close (fd); + + return result; } diff --git a/login/utmpd/connection.c b/login/utmpd/connection.c new file mode 100644 index 0000000000..4e1663189d --- /dev/null +++ b/login/utmpd/connection.c @@ -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); +} diff --git a/login/utmpd/database.c b/login/utmpd/database.c new file mode 100644 index 0000000000..e31e0d9dae --- /dev/null +++ b/login/utmpd/database.c @@ -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; +} diff --git a/login/utmpd/error.c b/login/utmpd/error.c new file mode 100644 index 0000000000..e6511442e3 --- /dev/null +++ b/login/utmpd/error.c @@ -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); +} diff --git a/login/utmpd/request.c b/login/utmpd/request.c new file mode 100644 index 0000000000..0f68b8ae79 --- /dev/null +++ b/login/utmpd/request.c @@ -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; +} diff --git a/login/utmpd/utmpd-private.h b/login/utmpd/utmpd-private.h new file mode 100644 index 0000000000..4a9cdb921e --- /dev/null +++ b/login/utmpd/utmpd-private.h @@ -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 */ + diff --git a/login/utmpd/utmpd.c b/login/utmpd/utmpd.c new file mode 100644 index 0000000000..e11218151c --- /dev/null +++ b/login/utmpd/utmpd.c @@ -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; +} + diff --git a/login/utmpd/utmpd.h b/login/utmpd/utmpd.h new file mode 100644 index 0000000000..8fbc33c923 --- /dev/null +++ b/login/utmpd/utmpd.h @@ -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 */ diff --git a/login/utmpd/xtmp.c b/login/utmpd/xtmp.c new file mode 100644 index 0000000000..d2d5feee3b --- /dev/null +++ b/login/utmpd/xtmp.c @@ -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); +} diff --git a/login/utmpd/xtmp.h b/login/utmpd/xtmp.h new file mode 100644 index 0000000000..8fa982ee4f --- /dev/null +++ b/login/utmpd/xtmp.h @@ -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 */ diff --git a/login/utmpdump.c b/login/utmpdump.c new file mode 100644 index 0000000000..e1422b5028 --- /dev/null +++ b/login/utmpdump.c @@ -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; +} diff --git a/login/utmpname.c b/login/utmpname.c new file mode 100644 index 0000000000..81e857a2bc --- /dev/null +++ b/login/utmpname.c @@ -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) diff --git a/math/Makefile b/math/Makefile index c2f3274877..e0c295b123 100644 --- a/math/Makefile +++ b/math/Makefile @@ -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 diff --git a/math/cmathcalls.h b/math/cmathcalls.h index 73a1c2a5da..1f74f56e0b 100644 --- a/math/cmathcalls.h +++ b/math/cmathcalls.h @@ -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. diff --git a/math/libm-test.c b/math/libm-test.c index 1f64d1ad24..866313e963 100644 --- a/math/libm-test.c +++ b/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 (); diff --git a/math/test-idouble.c b/math/test-idouble.c new file mode 100644 index 0000000000..614f10feb4 --- /dev/null +++ b/math/test-idouble.c @@ -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" diff --git a/math/test-ifloat.c b/math/test-ifloat.c new file mode 100644 index 0000000000..05e5de62ff --- /dev/null +++ b/math/test-ifloat.c @@ -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" diff --git a/math/test-ildoubl.c b/math/test-ildoubl.c new file mode 100644 index 0000000000..791cb95cf3 --- /dev/null +++ b/math/test-ildoubl.c @@ -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" diff --git a/math/test-longdouble.c b/math/test-ldouble.c index eb9b57ae96..eb9b57ae96 100644 --- a/math/test-longdouble.c +++ b/math/test-ldouble.c diff --git a/misc/regexp.h b/misc/regexp.h index f31b1af1d0..9ab25499a6 100644 --- a/misc/regexp.h +++ b/misc/regexp.h @@ -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 diff --git a/nis/nis_error.c b/nis/nis_error.c index 760dc518ab..6ed1cc914a 100644 --- a/nis/nis_error.c +++ b/nis/nis_error.c @@ -19,6 +19,7 @@ #include <errno.h> #include <syslog.h> +#include <string.h> #include <rpcsvc/nis.h> #include <rpcsvc/nislib.h> diff --git a/nis/nis_print.c b/nis/nis_print.c index e6eb264ae7..f829994245 100644 --- a/nis/nis_print.c +++ b/nis/nis_print.c @@ -18,6 +18,8 @@ Boston, MA 02111-1307, USA. */ #include <time.h> +#include <string.h> + #include <rpcsvc/nis.h> #include <rpcsvc/nislib.h> diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c index c933ae49be..6f1b4be35b 100644 --- a/nis/nss_nisplus/nisplus-hosts.c +++ b/nis/nss_nisplus/nisplus-hosts.c @@ -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); } diff --git a/nss/digits_dots.c b/nss/digits_dots.c index c953fc6ec6..e1baafa843 100644 --- a/nss/digits_dots.c +++ b/nss/digits_dots.c @@ -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. */ diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c index d6dd6daea7..f54691eec5 100644 --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -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); }) diff --git a/posix/execl.c b/posix/execl.c index 4772f15474..ad6190cf3d 100644 --- a/posix/execl.c +++ b/posix/execl.c @@ -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> diff --git a/resolv/Banner b/resolv/Banner index d11ab500fb..a792533a9e 100644 --- a/resolv/Banner +++ b/resolv/Banner @@ -1 +1 @@ -BIND-4.9.5-P1 +BIND-4.9.6-T1A diff --git a/resolv/base64.c b/resolv/base64.c index 5d9eb6ec3d..4e7e2a06d5 100644 --- a/resolv/base64.c +++ b/resolv/base64.c @@ -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); diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c index 114875b910..f2def79e24 100644 --- a/resolv/gethnamaddr.c +++ b/resolv/gethnamaddr.c @@ -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); } diff --git a/resolv/inet_net_pton.c b/resolv/inet_net_pton.c index 0c2693136d..bf6fe02ed8 100644 --- a/resolv/inet_net_pton.c +++ b/resolv/inet_net_pton.c @@ -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; diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 65a668e664..19ca33e197 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -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; } diff --git a/resolv/res_comp.c b/resolv/res_comp.c index a9ca69e55f..ed4bcdc58f 100644 --- a/resolv/res_comp.c +++ b/resolv/res_comp.c @@ -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) { diff --git a/resolv/res_debug.c b/resolv/res_debug.c index fa2ca80c34..3afe8c23a8 100644 --- a/resolv/res_debug.c +++ b/resolv/res_debug.c @@ -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); } diff --git a/resolv/res_init.c b/resolv/res_init.c index 91f9f40094..755b88d466 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -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; diff --git a/resolv/res_send.c b/resolv/res_send.c index 60d8ef2fb9..cde6a845d5 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -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); diff --git a/signal/tst-signal.c b/signal/tst-signal.c index 586d15c7e9..37e44a3a21 100644 --- a/signal/tst-signal.c +++ b/signal/tst-signal.c @@ -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; diff --git a/stdlib/testsort.c b/stdlib/testsort.c index 041de5caca..3ae55b14b9 100644 --- a/stdlib/testsort.c +++ b/stdlib/testsort.c @@ -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); } diff --git a/string/tester.c b/string/tester.c index 0a13a8c82e..23d0af8acb 100644 --- a/string/tester.c +++ b/string/tester.c @@ -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; diff --git a/sunrpc/rpc/svc.h b/sunrpc/rpc/svc.h index 6b308f356e..f7b05452cc 100644 --- a/sunrpc/rpc/svc.h +++ b/sunrpc/rpc/svc.h @@ -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)); /* diff --git a/sysdeps/generic/bzero.c b/sysdeps/generic/bzero.c index eaa359d77e..7fda7c3b5e 100644 --- a/sysdeps/generic/bzero.c +++ b/sysdeps/generic/bzero.c @@ -22,7 +22,7 @@ /* Set N bytes of S to 0. */ void -bzero (s, n) +bzero (s, len) void *s; size_t len; { diff --git a/sysdeps/generic/memccpy.c b/sysdeps/generic/memccpy.c index 8875abedd5..7c2d443863 100644 --- a/sysdeps/generic/memccpy.c +++ b/sysdeps/generic/memccpy.c @@ -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. diff --git a/sysdeps/generic/vtimes.c b/sysdeps/generic/vtimes.c index 298f428b71..0c19a918f8 100644 --- a/sysdeps/generic/vtimes.c +++ b/sysdeps/generic/vtimes.c @@ -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) { diff --git a/sysdeps/m68k/fpu/e_atan2.c b/sysdeps/m68k/fpu/e_atan2.c index c012070a93..59bc990f5b 100644 --- a/sysdeps/m68k/fpu/e_atan2.c +++ b/sysdeps/m68k/fpu/e_atan2.c @@ -35,63 +35,67 @@ 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); + if (-x > -y) + z = -pi + m81(__atan) (y / x); else - z = pi_2 - m81(__atan) (x / y); + z = -pi_2 - m81(__atan) (x / y); } else { - if (x > -y) - z = m81(__atan) (y / x); + if (-x > y) + z = pi + m81(__atan) (y / x); else - z = -pi_2 - m81(__atan) (x / y); + z = pi_2 - m81(__atan) (x / y); } } else { - if (y < 0) + if (y_cond & __M81_COND_NEG) { - if (-x > y) - z = -pi + m81(__atan) (y / x); + if (x > -y) + z = m81(__atan) (y / x); else z = -pi_2 - m81(__atan) (x / y); } else { - if (-x > y) - z = pi + m81(__atan) (y / x); + if (x > y) + z = m81(__atan) (y / x); else z = pi_2 - m81(__atan) (x / y); } diff --git a/sysdeps/unix/Makefile b/sysdeps/unix/Makefile index c9c5ed8fdc..f51dc508a0 100644 --- a/sysdeps/unix/Makefile +++ b/sysdeps/unix/Makefile @@ -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 diff --git a/sysdeps/unix/bsd/ualarm.c b/sysdeps/unix/bsd/ualarm.c index c153fb1705..b9a1409bab 100644 --- a/sysdeps/unix/bsd/ualarm.c +++ b/sysdeps/unix/bsd/ualarm.c @@ -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 diff --git a/sysdeps/unix/sysv/linux/net/ppp_defs.h b/sysdeps/unix/sysv/linux/net/ppp_defs.h index 5d613e0d0f..f8924c4f27 100644 --- a/sysdeps/unix/sysv/linux/net/ppp_defs.h +++ b/sysdeps/unix/sysv/linux/net/ppp_defs.h @@ -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> diff --git a/sysdeps/unix/sysv/linux/netinet/ip_fw.h b/sysdeps/unix/sysv/linux/netinet/ip_fw.h index 8ba10ae196..322467b5ff 100644 --- a/sysdeps/unix/sysv/linux/netinet/ip_fw.h +++ b/sysdeps/unix/sysv/linux/netinet/ip_fw.h @@ -53,6 +53,7 @@ #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> +#include <net/if.h> __BEGIN_DECLS diff --git a/sysdeps/wordsize-32/inttypes.h b/sysdeps/wordsize-32/inttypes.h index f9735a1309..97bfed5a0a 100644 --- a/sysdeps/wordsize-32/inttypes.h +++ b/sysdeps/wordsize-32/inttypes.h @@ -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. */ diff --git a/sysdeps/wordsize-64/inttypes.h b/sysdeps/wordsize-64/inttypes.h index a86e49c24f..663b7b1a8d 100644 --- a/sysdeps/wordsize-64/inttypes.h +++ b/sysdeps/wordsize-64/inttypes.h @@ -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. */ diff --git a/time/strftime.c b/time/strftime.c index 10d508d6e5..8c50a7dffb 100644 --- a/time/strftime.c +++ b/time/strftime.c @@ -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); \ diff --git a/time/strptime.c b/time/strptime.c index 90b88a1ba3..8d650716fe 100644 --- a/time/strptime.c +++ b/time/strptime.c @@ -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': |