diff options
Diffstat (limited to 'contrib/amd/libamu/xutil.c')
-rw-r--r-- | contrib/amd/libamu/xutil.c | 308 |
1 files changed, 223 insertions, 85 deletions
diff --git a/contrib/amd/libamu/xutil.c b/contrib/amd/libamu/xutil.c index 5095c23..3a33b9c 100644 --- a/contrib/amd/libamu/xutil.c +++ b/contrib/amd/libamu/xutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2004 Erez Zadok + * Copyright (c) 1997-2006 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. @@ -36,12 +36,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * %W% (Berkeley) %G% * - * $Id: xutil.c,v 1.11.2.13 2004/01/06 03:15:24 ezk Exp $ + * File: am-utils/libamu/xutil.c * */ +/* + * Miscellaneous Utilities: Logging, TTY, timers, signals, RPC, memory, etc. + */ + #ifdef HAVE_CONFIG_H # include <config.h> #endif /* HAVE_CONFIG_H */ @@ -56,13 +59,11 @@ FILE *logfp = NULL; static char *am_progname = "unknown"; /* "amd" */ -static char am_hostname[MAXHOSTNAMELEN + 1] = "unknown"; /* Hostname */ +static char am_hostname[MAXHOSTNAMELEN] = "unknown"; /* Hostname */ pid_t am_mypid = -1; /* process ID */ serv_state amd_state; /* amd's state */ int foreground = 1; /* 1 == this is the top-level server */ -#ifdef DEBUG int debug_flags = 0; -#endif /* DEBUG */ #ifdef HAVE_SYSLOG int syslogging; @@ -71,12 +72,11 @@ int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS; int xlog_level_init = ~0; static int amd_program_number = AMQ_PROGRAM; -time_t clock_valid = 0; -time_t xclock_valid = 0; - #ifdef DEBUG_MEM +# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) static int mem_bytes; static int orig_mem_bytes; +# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ #endif /* DEBUG_MEM */ /* forward definitions */ @@ -91,23 +91,21 @@ static void real_plog(int lvl, const char *fmt, va_list vargs) */ struct opt_tab dbg_opt[] = { - {"all", D_ALL}, /* All */ - {"amq", D_AMQ}, /* Register for AMQ program */ - {"daemon", D_DAEMON}, /* Enter daemon mode */ - {"fork", D_FORK}, /* Fork server (nofork = don't fork) */ + {"all", D_ALL}, /* All non-disruptive options */ + {"amq", D_AMQ}, /* Don't register for AMQ program */ + {"daemon", D_DAEMON}, /* Don't enter daemon mode */ + {"fork", D_FORK}, /* Don't fork server */ {"full", D_FULL}, /* Program trace */ #ifdef HAVE_CLOCK_GETTIME {"hrtime", D_HRTIME}, /* Print high resolution time stamps */ #endif /* HAVE_CLOCK_GETTIME */ /* info service specific debugging (hesiod, nis, etc) */ {"info", D_INFO}, -# ifdef DEBUG_MEM {"mem", D_MEM}, /* Trace memory allocations */ -# endif /* DEBUG_MEM */ {"mtab", D_MTAB}, /* Use local mtab file */ - {"readdir", D_READDIR}, /* check on browsable_dirs progress */ + {"readdir", D_READDIR}, /* Check on browsable_dirs progress */ {"str", D_STR}, /* Debug string munging */ - {"test", D_TEST}, /* Full debug - but no daemon */ + {"test", D_TEST}, /* Full debug - no daemon, no amq, local mtab */ {"trace", D_TRACE}, /* Protocol trace */ {"xdrtrace", D_XDRTRACE}, /* Trace xdr routines */ {0, 0} @@ -152,8 +150,7 @@ am_get_progname(void) void am_set_hostname(char *hn) { - strncpy(am_hostname, hn, MAXHOSTNAMELEN); - am_hostname[MAXHOSTNAMELEN] = '\0'; + xstrlcpy(am_hostname, hn, MAXHOSTNAMELEN); } @@ -172,6 +169,13 @@ am_set_mypid(void) } +long +get_server_pid() +{ + return (long) (foreground ? am_mypid : getppid()); +} + + voidp xmalloc(int len) { @@ -187,10 +191,8 @@ xmalloc(int len) do { p = (voidp) malloc((unsigned) len); if (p) { -#if defined(DEBUG) && defined(DEBUG_MEM) - amuDebug(D_MEM) - plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p); -#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ + if (amuDebug(D_MEM)) + plog(XLOG_DEBUG, "Allocated size %d; block %p", len, p); return p; } if (retries > 0) { @@ -223,9 +225,8 @@ xzalloc(int len) voidp xrealloc(voidp ptr, int len) { -#if defined(DEBUG) && defined(DEBUG_MEM) - amuDebug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr); -#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ + if (amuDebug(D_MEM)) + plog(XLOG_DEBUG, "Reallocated size %d; block %p", len, ptr); if (len == 0) len = 1; @@ -244,20 +245,19 @@ xrealloc(voidp ptr, int len) } -#if defined(DEBUG) && defined(DEBUG_MEM) +#ifdef DEBUG_MEM void dxfree(char *file, int line, voidp ptr) { - amuDebug(D_MEM) - plog(XLOG_DEBUG, "Free in %s:%d: block %#x", file, line, ptr); + if (amuDebug(D_MEM)) + plog(XLOG_DEBUG, "Free in %s:%d: block %p", file, line, ptr); /* this is the only place that must NOT use XFREE()!!! */ free(ptr); ptr = NULL; /* paranoid */ } -#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ -#ifdef DEBUG_MEM +# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) static void checkup_mem(void) { @@ -280,6 +280,7 @@ checkup_mem(void) } malloc_verify(); } +# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ #endif /* DEBUG_MEM */ @@ -289,16 +290,16 @@ checkup_mem(void) * 'e' never gets longer than maxlen characters. */ static const char * -expand_error(const char *f, char *e, int maxlen) +expand_error(const char *f, char *e, size_t maxlen) { const char *p; char *q; int error = errno; int len = 0; - for (p = f, q = e; (*q = *p) && len < maxlen; len++, q++, p++) { + for (p = f, q = e; (*q = *p) && (size_t) len < maxlen; len++, q++, p++) { if (p[0] == '%' && p[1] == 'm') { - strcpy(q, strerror(error)); + xstrlcpy(q, strerror(error), maxlen); len += strlen(q) - 1; q += strlen(q) - 1; p++; @@ -318,27 +319,27 @@ show_time_host_and_name(int lvl) static time_t last_t = 0; static char *last_ctime = 0; time_t t; -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) struct timespec ts; -#endif /* HAVE_CLOCK_GETTIME */ - char nsecs[11] = ""; /* '.' + 9 digits + '\0' */ +#endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ + char nsecs[11]; /* '.' + 9 digits + '\0' */ char *sev; -#ifdef HAVE_CLOCK_GETTIME + nsecs[0] = '\0'; + +#if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) /* * Some systems (AIX 4.3) seem to implement clock_gettime() as stub * returning ENOSYS. */ if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { t = ts.tv_sec; -#ifdef DEBUG - amuDebug(D_HRTIME) - sprintf(nsecs, ".%09ld", ts.tv_nsec); -#endif /* DEBUG */ + if (amuDebug(D_HRTIME)) + xsnprintf(nsecs, sizeof(nsecs), ".%09ld", ts.tv_nsec); } else -#endif /* HAVE_CLOCK_GETTIME */ - t = clocktime(); +#endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ + t = clocktime(NULL); if (t != last_t) { last_ctime = ctime(&t); @@ -435,29 +436,20 @@ real_plog(int lvl, const char *fmt, va_list vargs) return; #ifdef DEBUG_MEM +# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) checkup_mem(); +# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ #endif /* DEBUG_MEM */ -#ifdef HAVE_VSNPRINTF - /* - * XXX: ptr is 1024 bytes long, but we may write to ptr[strlen(ptr) + 2] - * (to add an '\n', see code below) so we have to limit the string copy - * to 1023 (including the '\0'). - */ - vsnprintf(ptr, 1023, expand_error(fmt, efmt, 1024), vargs); - msg[1022] = '\0'; /* null terminate, to be sure */ -#else /* not HAVE_VSNPRINTF */ /* - * XXX: ptr is 1024 bytes long. It is possible to write into it - * more than 1024 bytes, if efmt is already large, and vargs expand - * as well. This is not as safe as using vsnprintf(). + * Note: xvsnprintf() may call plog() if a truncation happened, but the + * latter has some code to break out of an infinite loop. See comment in + * xsnprintf() below. */ - vsprintf(ptr, expand_error(fmt, efmt, 1023), vargs); - msg[1023] = '\0'; /* null terminate, to be sure */ -#endif /* not HAVE_VSNPRINTF */ + xvsnprintf(ptr, 1023, expand_error(fmt, efmt, 1024), vargs); ptr += strlen(ptr); - if (ptr[-1] == '\n') + if (*(ptr-1) == '\n') *--ptr = '\0'; #ifdef HAVE_SYSLOG @@ -505,7 +497,8 @@ real_plog(int lvl, const char *fmt, va_list vargs) switch (last_count) { case 0: /* never printed at all */ last_count = 1; - strncpy(last_msg, msg, 1024); + if (strlcpy(last_msg, msg, 1024) >= 1024) /* don't use xstrlcpy here (recursive!) */ + fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); last_lvl = lvl; show_time_host_and_name(lvl); /* mimic syslog header */ fwrite(msg, ptr - msg, 1, logfp); @@ -517,7 +510,8 @@ real_plog(int lvl, const char *fmt, va_list vargs) last_count++; } else { /* last msg printed once, new one differs */ /* last_count remains at 1 */ - strncpy(last_msg, msg, 1024); + if (strlcpy(last_msg, msg, 1024) >= 1024) /* don't use xstrlcpy here (recursive!) */ + fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); last_lvl = lvl; show_time_host_and_name(lvl); /* mimic syslog header */ fwrite(msg, ptr - msg, 1, logfp); @@ -531,7 +525,8 @@ real_plog(int lvl, const char *fmt, va_list vargs) * cycles like crazy. */ show_time_host_and_name(last_lvl); - sprintf(last_msg, "last message repeated %d times\n", last_count); + xsnprintf(last_msg, sizeof(last_msg), + "last message repeated %d times\n", last_count); fwrite(last_msg, strlen(last_msg), 1, logfp); fflush(logfp); last_count = 0; /* start from scratch */ @@ -542,9 +537,11 @@ real_plog(int lvl, const char *fmt, va_list vargs) last_count++; } else { /* last msg repeated+skipped, new one differs */ show_time_host_and_name(last_lvl); - sprintf(last_msg, "last message repeated %d times\n", last_count); + xsnprintf(last_msg, sizeof(last_msg), + "last message repeated %d times\n", last_count); fwrite(last_msg, strlen(last_msg), 1, logfp); - strncpy(last_msg, msg, 1024); + if (strlcpy(last_msg, msg, 1024) >= 1024) /* don't use xstrlcpy here (recursive!) */ + fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); last_count = 1; last_lvl = lvl; show_time_host_and_name(lvl); /* mimic syslog header */ @@ -667,6 +664,7 @@ switch_option(char *opt) return rc; } + #ifdef LOG_DAEMON /* * get syslog facility to use. @@ -771,7 +769,7 @@ get_syslog_facility(const char *logfile) * Change current logfile */ int -switch_to_logfile(char *logfile, int old_umask) +switch_to_logfile(char *logfile, int old_umask, int truncate_log) { FILE *new_logfp = stderr; @@ -789,9 +787,6 @@ switch_to_logfile(char *logfile, int old_umask) new_logfp = stderr; openlog(am_get_progname(), LOG_PID -# ifdef LOG_CONS - | LOG_CONS -# endif /* LOG_CONS */ # ifdef LOG_NOWAIT | LOG_NOWAIT # endif /* LOG_NOWAIT */ @@ -803,8 +798,10 @@ switch_to_logfile(char *logfile, int old_umask) plog(XLOG_WARNING, "syslog option not supported, logging unchanged"); #endif /* not HAVE_SYSLOG */ - } else { + } else { /* regular log file */ (void) umask(old_umask); + if (truncate_log) + truncate(logfile, 0); new_logfp = fopen(logfile, "a"); umask(0); } @@ -837,11 +834,14 @@ switch_to_logfile(char *logfile, int old_umask) void unregister_amq(void) { -#ifdef DEBUG - amuDebug(D_AMQ) -#endif /* DEBUG */ + if (!amuDebug(D_AMQ)) { /* find which instance of amd to unregister */ - pmap_unset(get_amd_program_number(), AMQ_VERSION); + u_long amd_prognum = get_amd_program_number(); + + if (pmap_unset(amd_prognum, AMQ_VERSION) != 1) + dlog("failed to de-register Amd program %lu, version %lu", + amd_prognum, AMQ_VERSION); + } } @@ -855,14 +855,21 @@ going_down(int rc) unregister_amq(); } } + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Call unlock_mntlist to free any important resources such as an on-disk + * lock file (/etc/mtab~). + */ + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ + if (foreground) { plog(XLOG_INFO, "Finishing with status %d", rc); } else { -#ifdef DEBUG dlog("background process exiting with status %d", rc); -#endif /* DEBUG */ } - + /* bye bye... */ exit(rc); } @@ -896,10 +903,7 @@ set_amd_program_number(int program) void amu_release_controlling_tty(void) { -#ifdef TIOCNOTTY int fd; -#endif /* TIOCNOTTY */ - int tempfd; /* * In daemon mode, leaving open file descriptors to terminals or pipes @@ -917,11 +921,15 @@ amu_release_controlling_tty(void) * * XXX We should also probably set the SIGPIPE handler to SIG_IGN. */ - tempfd = open("/dev/null", O_RDWR); - fflush(stdin); close(0); dup2(tempfd, 0); - fflush(stdout); close(1); dup2(tempfd, 1); - fflush(stderr); close(2); dup2(tempfd, 2); - close(tempfd); + fd = open("/dev/null", O_RDWR); + if (fd < 0) { + plog(XLOG_WARNING, "Could not open /dev/null for rw: %m"); + } else { + fflush(stdin); close(0); dup2(fd, 0); + fflush(stdout); close(1); dup2(fd, 1); + fflush(stderr); close(2); dup2(fd, 2); + close(fd); + } #ifdef HAVE_SETSID /* XXX: one day maybe use vhangup(2) */ @@ -951,3 +959,133 @@ amu_release_controlling_tty(void) plog(XLOG_ERROR, "unable to release controlling tty"); } + + +/* setup a single signal handler */ +void +setup_sighandler(int signum, void (*handler)(int)) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = 0; /* unnecessary */ + sa.sa_handler = handler; + sigemptyset(&(sa.sa_mask)); /* probably unnecessary too */ + sigaddset(&(sa.sa_mask), signum); + sigaction(signum, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(signum, handler); +#endif /* not HAVE_SIGACTION */ +} + + +/* + * Return current time in seconds. If passed a non-null argyument, then + * fill it in with the current time in seconds and microseconds (useful + * for mtime updates). + */ +time_t +clocktime(nfstime *nt) +{ + static struct timeval now; /* keep last time, as default */ + + if (gettimeofday(&now, NULL) < 0) { + plog(XLOG_ERROR, "clocktime: gettimeofday: %m"); + /* hack: force time to have incremented by at least 1 second */ + now.tv_sec++; + } + /* copy seconds and microseconds. may demote a long to an int */ + if (nt) { + nt->nt_seconds = (u_int) now.tv_sec; + nt->nt_useconds = (u_int) now.tv_usec; + } + return (time_t) now.tv_sec; +} + + +/* + * Make all the directories in the path. + */ +int +mkdirs(char *path, int mode) +{ + /* + * take a copy in case path is in readonly store + */ + char *p2 = strdup(path); + char *sp = p2; + struct stat stb; + int error_so_far = 0; + + /* + * Skip through the string make the directories. + * Mostly ignore errors - the result is tested at the end. + * + * This assumes we are root so that we can do mkdir in a + * mode 555 directory... + */ + while ((sp = strchr(sp + 1, '/'))) { + *sp = '\0'; + if (mkdir(p2, mode) < 0) { + error_so_far = errno; + } else { + dlog("mkdir(%s)", p2); + } + *sp = '/'; + } + + if (mkdir(p2, mode) < 0) { + error_so_far = errno; + } else { + dlog("mkdir(%s)", p2); + } + + XFREE(p2); + + return stat(path, &stb) == 0 && + (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far; +} + + +/* + * Remove as many directories in the path as possible. + * Give up if the directory doesn't appear to have + * been created by Amd (not mode dr-x) or an rmdir + * fails for any reason. + */ +void +rmdirs(char *dir) +{ + char *xdp = strdup(dir); + char *dp; + + do { + struct stat stb; + /* + * Try to find out whether this was + * created by amd. Do this by checking + * for owner write permission. + */ + if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) { + if (rmdir(xdp) < 0) { + if (errno != ENOTEMPTY && + errno != EBUSY && + errno != EEXIST && + errno != EROFS && + errno != EINVAL) + plog(XLOG_ERROR, "rmdir(%s): %m", xdp); + break; + } else { + dlog("rmdir(%s)", xdp); + } + } else { + break; + } + + dp = strrchr(xdp, '/'); + if (dp) + *dp = '\0'; + } while (dp && dp > xdp); + + XFREE(xdp); +} |