138494Sobrien/* 2310490Scy * Copyright (c) 1997-2014 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 2038494Sobrien * may be used to endorse or promote products derived from this software 2138494Sobrien * without specific prior written permission. 2238494Sobrien * 2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2638494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3338494Sobrien * SUCH DAMAGE. 3438494Sobrien * 3538494Sobrien * 36174294Sobrien * File: am-utils/libamu/xutil.c 3738494Sobrien * 3838494Sobrien */ 3938494Sobrien 40174294Sobrien/* 41174294Sobrien * Miscellaneous Utilities: Logging, TTY, timers, signals, RPC, memory, etc. 42174294Sobrien */ 43174294Sobrien 4438494Sobrien#ifdef HAVE_CONFIG_H 4538494Sobrien# include <config.h> 4638494Sobrien#endif /* HAVE_CONFIG_H */ 4738494Sobrien#include <am_defs.h> 4838494Sobrien#include <amu.h> 4938494Sobrien 5051292Sobrien/* 5151292Sobrien * Logfp is the default logging device, and is initialized to stderr by 5251292Sobrien * default in dplog/plog below, and in 5351292Sobrien * amd/amfs_program.c:amfs_program_exec(). 5451292Sobrien */ 5551292SobrienFILE *logfp = NULL; 5638494Sobrien 5742629Sobrienstatic char *am_progname = "unknown"; /* "amd" */ 58174294Sobrienstatic char am_hostname[MAXHOSTNAMELEN] = "unknown"; /* Hostname */ 5942629Sobrienpid_t am_mypid = -1; /* process ID */ 6042629Sobrienserv_state amd_state; /* amd's state */ 6142629Sobrienint foreground = 1; /* 1 == this is the top-level server */ 62310490Scyu_int debug_flags = D_CONTROL; /* set regardless if compiled with debugging */ 6342629Sobrien 6438494Sobrien#ifdef HAVE_SYSLOG 6538494Sobrienint syslogging; 6638494Sobrien#endif /* HAVE_SYSLOG */ 67310490Scystatic u_int xlog_level = XLOG_DEFAULT; 68310490Scystatic u_long amd_program_number = AMQ_PROGRAM; 6938494Sobrien 7038494Sobrien#ifdef DEBUG_MEM 71174294Sobrien# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) 7238494Sobrienstatic int mem_bytes; 7338494Sobrienstatic int orig_mem_bytes; 74174294Sobrien# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ 7538494Sobrien#endif /* DEBUG_MEM */ 7638494Sobrien 7738494Sobrien/* forward definitions */ 78119679Smbr/* for GCC format string auditing */ 7982794Sobrienstatic void real_plog(int lvl, const char *fmt, va_list vargs) 8082794Sobrien __attribute__((__format__(__printf__, 2, 0))); 8138494Sobrien 82119679Smbr 8338494Sobrien#ifdef DEBUG 8438494Sobrien/* 8538494Sobrien * List of debug options. 8638494Sobrien */ 8738494Sobrienstruct opt_tab dbg_opt[] = 8838494Sobrien{ 89174294Sobrien {"all", D_ALL}, /* All non-disruptive options */ 90310490Scy {"defaults", D_DEFAULT}, /* Default options */ 91310490Scy {"test", D_TEST}, /* Full debug - no daemon, no fork, no amq, local mtab */ 92310490Scy {"amq", D_AMQ}, /* Register for AMQ program */ 93310490Scy {"daemon", D_DAEMON}, /* Enter daemon mode */ 94310490Scy {"fork", D_FORK}, /* Fork server (hlfsd only) */ 9538494Sobrien {"full", D_FULL}, /* Program trace */ 9682794Sobrien#ifdef HAVE_CLOCK_GETTIME 9782794Sobrien {"hrtime", D_HRTIME}, /* Print high resolution time stamps */ 9882794Sobrien#endif /* HAVE_CLOCK_GETTIME */ 99310490Scy {"info", D_INFO}, /* info service specific debugging (hesiod, nis, etc) */ 10038494Sobrien {"mem", D_MEM}, /* Trace memory allocations */ 10138494Sobrien {"mtab", D_MTAB}, /* Use local mtab file */ 102174294Sobrien {"readdir", D_READDIR}, /* Check on browsable_dirs progress */ 10338494Sobrien {"str", D_STR}, /* Debug string munging */ 10438494Sobrien {"trace", D_TRACE}, /* Protocol trace */ 10582794Sobrien {"xdrtrace", D_XDRTRACE}, /* Trace xdr routines */ 106310490Scy {NULL, 0} 10738494Sobrien}; 10838494Sobrien#endif /* DEBUG */ 10938494Sobrien 11038494Sobrien/* 11138494Sobrien * List of log options 11238494Sobrien */ 11338494Sobrienstruct opt_tab xlog_opt[] = 11438494Sobrien{ 11538494Sobrien {"all", XLOG_ALL}, /* All messages */ 116310490Scy {"defaults", XLOG_DEFAULT}, /* Default messages */ 11738494Sobrien#ifdef DEBUG 11838494Sobrien {"debug", XLOG_DEBUG}, /* Debug messages */ 11938494Sobrien#endif /* DEBUG */ /* DEBUG */ 12038494Sobrien {"error", XLOG_ERROR}, /* Non-fatal system errors */ 12138494Sobrien {"fatal", XLOG_FATAL}, /* Fatal errors */ 12238494Sobrien {"info", XLOG_INFO}, /* Information */ 12338494Sobrien {"map", XLOG_MAP}, /* Map errors */ 12438494Sobrien {"stats", XLOG_STATS}, /* Additional statistical information */ 12538494Sobrien {"user", XLOG_USER}, /* Non-fatal user errors */ 12638494Sobrien {"warn", XLOG_WARNING}, /* Warnings */ 12738494Sobrien {"warning", XLOG_WARNING}, /* Warnings */ 128310490Scy {NULL, 0} 12938494Sobrien}; 13038494Sobrien 13138494Sobrien 13242629Sobrienvoid 13342629Sobrienam_set_progname(char *pn) 13442629Sobrien{ 13542629Sobrien am_progname = pn; 13642629Sobrien} 13742629Sobrien 13842629Sobrien 13942629Sobrienconst char * 14042629Sobrienam_get_progname(void) 14142629Sobrien{ 14242629Sobrien return am_progname; 14342629Sobrien} 14442629Sobrien 14542629Sobrien 14642629Sobrienvoid 14742629Sobrienam_set_hostname(char *hn) 14842629Sobrien{ 149310490Scy xstrlcpy(am_hostname, hn, sizeof(am_hostname)); 15042629Sobrien} 15142629Sobrien 15242629Sobrien 15342629Sobrienconst char * 15442629Sobrienam_get_hostname(void) 15542629Sobrien{ 15642629Sobrien return am_hostname; 15742629Sobrien} 15842629Sobrien 15942629Sobrien 16042629Sobrienpid_t 16142629Sobrienam_set_mypid(void) 16242629Sobrien{ 16342629Sobrien am_mypid = getpid(); 16442629Sobrien return am_mypid; 16542629Sobrien} 16642629Sobrien 16742629Sobrien 168174294Sobrienlong 169174294Sobrienget_server_pid() 170174294Sobrien{ 171174294Sobrien return (long) (foreground ? am_mypid : getppid()); 172174294Sobrien} 173174294Sobrien 174174294Sobrien 17538494Sobrienvoidp 17638494Sobrienxmalloc(int len) 17738494Sobrien{ 17838494Sobrien voidp p; 17938494Sobrien int retries = 600; 18038494Sobrien 18138494Sobrien /* 18238494Sobrien * Avoid malloc's which return NULL for malloc(0) 18338494Sobrien */ 18438494Sobrien if (len == 0) 18538494Sobrien len = 1; 18638494Sobrien 18738494Sobrien do { 18838494Sobrien p = (voidp) malloc((unsigned) len); 18938494Sobrien if (p) { 190174294Sobrien if (amuDebug(D_MEM)) 191174294Sobrien plog(XLOG_DEBUG, "Allocated size %d; block %p", len, p); 19238494Sobrien return p; 19338494Sobrien } 19438494Sobrien if (retries > 0) { 19538494Sobrien plog(XLOG_ERROR, "Retrying memory allocation"); 19638494Sobrien sleep(1); 19738494Sobrien } 19838494Sobrien } while (--retries); 19938494Sobrien 20038494Sobrien plog(XLOG_FATAL, "Out of memory"); 20138494Sobrien going_down(1); 20238494Sobrien 20338494Sobrien abort(); 20438494Sobrien 20538494Sobrien return 0; 20638494Sobrien} 20738494Sobrien 20838494Sobrien 20938494Sobrien/* like xmalloc, but zeros out the bytes */ 21038494Sobrienvoidp 21138494Sobrienxzalloc(int len) 21238494Sobrien{ 21338494Sobrien voidp p = xmalloc(len); 21438494Sobrien 21538494Sobrien if (p) 21638494Sobrien memset(p, 0, len); 21738494Sobrien return p; 21838494Sobrien} 21938494Sobrien 22038494Sobrien 22138494Sobrienvoidp 22238494Sobrienxrealloc(voidp ptr, int len) 22338494Sobrien{ 224174294Sobrien if (amuDebug(D_MEM)) 225174294Sobrien plog(XLOG_DEBUG, "Reallocated size %d; block %p", len, ptr); 22638494Sobrien 22738494Sobrien if (len == 0) 22838494Sobrien len = 1; 22938494Sobrien 23038494Sobrien if (ptr) 23138494Sobrien ptr = (voidp) realloc(ptr, (unsigned) len); 23238494Sobrien else 23338494Sobrien ptr = (voidp) xmalloc((unsigned) len); 23438494Sobrien 23538494Sobrien if (!ptr) { 23638494Sobrien plog(XLOG_FATAL, "Out of memory in realloc"); 23738494Sobrien going_down(1); 23838494Sobrien abort(); 23938494Sobrien } 24038494Sobrien return ptr; 24138494Sobrien} 24238494Sobrien 24338494Sobrien 244174294Sobrien#ifdef DEBUG_MEM 24538494Sobrienvoid 24638494Sobriendxfree(char *file, int line, voidp ptr) 24738494Sobrien{ 248174294Sobrien if (amuDebug(D_MEM)) 249174294Sobrien plog(XLOG_DEBUG, "Free in %s:%d: block %p", file, line, ptr); 25038494Sobrien /* this is the only place that must NOT use XFREE()!!! */ 25138494Sobrien free(ptr); 25238494Sobrien ptr = NULL; /* paranoid */ 25338494Sobrien} 25438494Sobrien 25538494Sobrien 256174294Sobrien# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) 25738494Sobrienstatic void 25838494Sobriencheckup_mem(void) 25938494Sobrien{ 26038494Sobrien struct mallinfo mi = mallinfo(); 26138494Sobrien u_long uordbytes = mi.uordblks * 4096; 26238494Sobrien 26338494Sobrien if (mem_bytes != uordbytes) { 26438494Sobrien if (orig_mem_bytes == 0) 26538494Sobrien mem_bytes = orig_mem_bytes = uordbytes; 26638494Sobrien else { 26742629Sobrien fprintf(logfp, "%s[%ld]: ", am_get_progname(), (long) am_mypid); 26838494Sobrien if (mem_bytes < uordbytes) { 26938494Sobrien fprintf(logfp, "ALLOC: %ld bytes", uordbytes - mem_bytes); 27038494Sobrien } else { 27138494Sobrien fprintf(logfp, "FREE: %ld bytes", mem_bytes - uordbytes); 27238494Sobrien } 27338494Sobrien mem_bytes = uordbytes; 27438494Sobrien fprintf(logfp, ", making %d missing\n", mem_bytes - orig_mem_bytes); 27538494Sobrien } 27638494Sobrien } 27738494Sobrien malloc_verify(); 27838494Sobrien} 279174294Sobrien# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ 28038494Sobrien#endif /* DEBUG_MEM */ 28138494Sobrien 28238494Sobrien 28338494Sobrien/* 28442629Sobrien * Take a log format string and expand occurrences of %m 28551292Sobrien * with the current error code taken from errno. Make sure 28651292Sobrien * 'e' never gets longer than maxlen characters. 28738494Sobrien */ 28882794Sobrienstatic const char * 289174294Sobrienexpand_error(const char *f, char *e, size_t maxlen) 29038494Sobrien{ 29182794Sobrien const char *p; 29282794Sobrien char *q; 29338494Sobrien int error = errno; 294310490Scy size_t len = 0, l; 29538494Sobrien 296310490Scy *e = '\0'; 297310490Scy for (p = f, q = e; len < maxlen && (*q = *p); len++, q++, p++) { 29838494Sobrien if (p[0] == '%' && p[1] == 'm') { 299310490Scy if (len >= maxlen) 300310490Scy break; 301310490Scy xstrlcpy(q, strerror(error), maxlen - len); 302310490Scy l = strlen(q); 303310490Scy if (l != 0) 304310490Scy l--; 305310490Scy len += l; 306310490Scy q += l; 30738494Sobrien p++; 30838494Sobrien } 30938494Sobrien } 310310490Scy e[maxlen - 1] = '\0'; /* null terminate, to be sure */ 31182794Sobrien return e; 31238494Sobrien} 31338494Sobrien 31438494Sobrien 31538494Sobrien/* 31638494Sobrien * Output the time of day and hostname to the logfile 31738494Sobrien */ 31838494Sobrienstatic void 31938494Sobrienshow_time_host_and_name(int lvl) 32038494Sobrien{ 32138494Sobrien static time_t last_t = 0; 322310490Scy static char *last_ctime = NULL; 32382794Sobrien time_t t; 324174294Sobrien#if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) 32582794Sobrien struct timespec ts; 326174294Sobrien#endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ 327174294Sobrien char nsecs[11]; /* '.' + 9 digits + '\0' */ 32838494Sobrien char *sev; 32938494Sobrien 330174294Sobrien nsecs[0] = '\0'; 331174294Sobrien 332174294Sobrien#if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) 33382794Sobrien /* 33482794Sobrien * Some systems (AIX 4.3) seem to implement clock_gettime() as stub 33582794Sobrien * returning ENOSYS. 33682794Sobrien */ 33782794Sobrien if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { 33882794Sobrien t = ts.tv_sec; 339174294Sobrien if (amuDebug(D_HRTIME)) 340174294Sobrien xsnprintf(nsecs, sizeof(nsecs), ".%09ld", ts.tv_nsec); 34182794Sobrien } 34282794Sobrien else 343174294Sobrien#endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */ 344174294Sobrien t = clocktime(NULL); 34582794Sobrien 34638494Sobrien if (t != last_t) { 34738494Sobrien last_ctime = ctime(&t); 34838494Sobrien last_t = t; 34938494Sobrien } 35082794Sobrien 35138494Sobrien switch (lvl) { 35238494Sobrien case XLOG_FATAL: 35338494Sobrien sev = "fatal:"; 35438494Sobrien break; 35538494Sobrien case XLOG_ERROR: 35638494Sobrien sev = "error:"; 35738494Sobrien break; 35838494Sobrien case XLOG_USER: 35938494Sobrien sev = "user: "; 36038494Sobrien break; 36138494Sobrien case XLOG_WARNING: 36238494Sobrien sev = "warn: "; 36338494Sobrien break; 36438494Sobrien case XLOG_INFO: 36538494Sobrien sev = "info: "; 36638494Sobrien break; 36738494Sobrien case XLOG_DEBUG: 36838494Sobrien sev = "debug:"; 36938494Sobrien break; 37038494Sobrien case XLOG_MAP: 37138494Sobrien sev = "map: "; 37238494Sobrien break; 37338494Sobrien case XLOG_STATS: 37438494Sobrien sev = "stats:"; 37538494Sobrien break; 37638494Sobrien default: 37738494Sobrien sev = "hmm: "; 37838494Sobrien break; 37938494Sobrien } 38082794Sobrien fprintf(logfp, "%15.15s%s %s %s[%ld]/%s ", 38182794Sobrien last_ctime + 4, nsecs, am_get_hostname(), 38242629Sobrien am_get_progname(), 38342629Sobrien (long) am_mypid, 38438494Sobrien sev); 38538494Sobrien} 38638494Sobrien 38738494Sobrien 38838494Sobrien#ifdef DEBUG 38938494Sobrien/* 39038494Sobrien * Switch on/off debug options 39138494Sobrien */ 39238494Sobrienint 39338494Sobriendebug_option(char *opt) 39438494Sobrien{ 395310490Scy u_int dl = debug_flags; 396310490Scy static int initialized_debug_flags = 0; 397310490Scy int rc = cmdoption(opt, dbg_opt, &dl); 398310490Scy 399310490Scy if (rc) /* if got any error, don't update debug flags */ 400310490Scy return EINVAL; 401310490Scy 402310490Scy /* 403310490Scy * If we already initialized the debugging flags once (via amd.conf), then 404310490Scy * don't allow "immutable" flags to be changed again (via amq -D), because 405310490Scy * they could mess Amd's state and only make sense to be set once when Amd 406310490Scy * starts. 407310490Scy */ 408310490Scy if (initialized_debug_flags && 409310490Scy debug_flags != 0 && 410310490Scy (dl & D_IMMUTABLE) != (debug_flags & D_IMMUTABLE)) { 411310490Scy plog(XLOG_ERROR, "cannot change immutable debug flags"); 412310490Scy /* undo any attempted change to an immutable flag */ 413310490Scy dl = (dl & ~D_IMMUTABLE) | (debug_flags & D_IMMUTABLE); 414310490Scy } 415310490Scy initialized_debug_flags = 1; 416310490Scy debug_flags = dl; 417310490Scy 418310490Scy return rc; 41938494Sobrien} 42038494Sobrien 42138494Sobrien 42238494Sobrienvoid 42382794Sobriendplog(const char *fmt, ...) 42438494Sobrien{ 425310490Scy#ifdef HAVE_SIGACTION 426310490Scy sigset_t old, chld; 427310490Scy#else /* not HAVE_SIGACTION */ 428310490Scy int mask; 429310490Scy#endif /* not HAVE_SIGACTION */ 43038494Sobrien va_list ap; 43138494Sobrien 432310490Scy#ifdef HAVE_SIGACTION 433310490Scy sigemptyset(&chld); 434310490Scy sigaddset(&chld, SIGCHLD); 435310490Scy#else /* not HAVE_SIGACTION */ 436310490Scy mask = sigblock(sigmask(SIGCHLD)); 437310490Scy#endif /* not HAVE_SIGACTION */ 438310490Scy 439310490Scy sigprocmask(SIG_BLOCK, &chld, &old); 44051292Sobrien if (!logfp) 44151292Sobrien logfp = stderr; /* initialize before possible first use */ 44251292Sobrien 44338494Sobrien va_start(ap, fmt); 44438494Sobrien real_plog(XLOG_DEBUG, fmt, ap); 44538494Sobrien va_end(ap); 446310490Scy 447310490Scy#ifdef HAVE_SIGACTION 448310490Scy sigprocmask(SIG_SETMASK, &old, NULL); 449310490Scy#else /* not HAVE_SIGACTION */ 450310490Scy mask = sigblock(sigmask(SIGCHLD)); 451310490Scy#endif /* not HAVE_SIGACTION */ 45238494Sobrien} 45338494Sobrien#endif /* DEBUG */ 45438494Sobrien 45538494Sobrien 45638494Sobrienvoid 45782794Sobrienplog(int lvl, const char *fmt, ...) 45838494Sobrien{ 459310490Scy#ifdef HAVE_SIGACTION 460310490Scy sigset_t old, chld; 461310490Scy#else /* not HAVE_SIGACTION */ 462310490Scy int mask; 463310490Scy#endif /* not HAVE_SIGACTION */ 46438494Sobrien va_list ap; 46538494Sobrien 466310490Scy#ifdef HAVE_SIGACTION 467310490Scy sigemptyset(&chld); 468310490Scy sigaddset(&chld, SIGCHLD); 469310490Scy sigprocmask(SIG_BLOCK, &chld, &old); 470310490Scy#else /* not HAVE_SIGACTION */ 471310490Scy mask = sigblock(sigmask(SIGCHLD)); 472310490Scy#endif /* not HAVE_SIGACTION */ 473310490Scy 47451292Sobrien if (!logfp) 47551292Sobrien logfp = stderr; /* initialize before possible first use */ 47651292Sobrien 47738494Sobrien va_start(ap, fmt); 47838494Sobrien real_plog(lvl, fmt, ap); 47938494Sobrien va_end(ap); 480310490Scy 481310490Scy#ifdef HAVE_SIGACTION 482310490Scy sigprocmask(SIG_SETMASK, &old, NULL); 483310490Scy#else /* not HAVE_SIGACTION */ 484310490Scy sigsetmask(mask); 485310490Scy#endif /* not HAVE_SIGACTION */ 48638494Sobrien} 48738494Sobrien 48838494Sobrien 48938494Sobrienstatic void 49082794Sobrienreal_plog(int lvl, const char *fmt, va_list vargs) 49138494Sobrien{ 49238494Sobrien char msg[1024]; 49338494Sobrien char efmt[1024]; 49438494Sobrien char *ptr = msg; 49538494Sobrien static char last_msg[1024]; 49638494Sobrien static int last_count = 0, last_lvl = 0; 49738494Sobrien 49838494Sobrien if (!(xlog_level & lvl)) 49938494Sobrien return; 50038494Sobrien 50138494Sobrien#ifdef DEBUG_MEM 502174294Sobrien# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) 50338494Sobrien checkup_mem(); 504174294Sobrien# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ 50538494Sobrien#endif /* DEBUG_MEM */ 50638494Sobrien 50782794Sobrien /* 508174294Sobrien * Note: xvsnprintf() may call plog() if a truncation happened, but the 509174294Sobrien * latter has some code to break out of an infinite loop. See comment in 510174294Sobrien * xsnprintf() below. 51182794Sobrien */ 512174294Sobrien xvsnprintf(ptr, 1023, expand_error(fmt, efmt, 1024), vargs); 51338494Sobrien 51438494Sobrien ptr += strlen(ptr); 515174294Sobrien if (*(ptr-1) == '\n') 51638494Sobrien *--ptr = '\0'; 51738494Sobrien 51838494Sobrien#ifdef HAVE_SYSLOG 51938494Sobrien if (syslogging) { 52038494Sobrien switch (lvl) { /* from mike <mcooper@usc.edu> */ 52138494Sobrien case XLOG_FATAL: 52238494Sobrien lvl = LOG_CRIT; 52338494Sobrien break; 52438494Sobrien case XLOG_ERROR: 52538494Sobrien lvl = LOG_ERR; 52638494Sobrien break; 52738494Sobrien case XLOG_USER: 52838494Sobrien lvl = LOG_WARNING; 52938494Sobrien break; 53038494Sobrien case XLOG_WARNING: 53138494Sobrien lvl = LOG_WARNING; 53238494Sobrien break; 53338494Sobrien case XLOG_INFO: 53438494Sobrien lvl = LOG_INFO; 53538494Sobrien break; 53638494Sobrien case XLOG_DEBUG: 53738494Sobrien lvl = LOG_DEBUG; 53838494Sobrien break; 53938494Sobrien case XLOG_MAP: 54038494Sobrien lvl = LOG_DEBUG; 54138494Sobrien break; 54238494Sobrien case XLOG_STATS: 54338494Sobrien lvl = LOG_INFO; 54438494Sobrien break; 54538494Sobrien default: 54638494Sobrien lvl = LOG_ERR; 54738494Sobrien break; 54838494Sobrien } 54938494Sobrien syslog(lvl, "%s", msg); 55038494Sobrien return; 55138494Sobrien } 55238494Sobrien#endif /* HAVE_SYSLOG */ 55338494Sobrien 55438494Sobrien *ptr++ = '\n'; 55538494Sobrien *ptr = '\0'; 55638494Sobrien 55738494Sobrien /* 55838494Sobrien * mimic syslog behavior: only write repeated strings if they differ 55938494Sobrien */ 56038494Sobrien switch (last_count) { 56138494Sobrien case 0: /* never printed at all */ 56238494Sobrien last_count = 1; 563310490Scy if (strlcpy(last_msg, msg, sizeof(last_msg)) >= sizeof(last_msg)) /* don't use xstrlcpy here (recursive!) */ 564174294Sobrien fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); 56538494Sobrien last_lvl = lvl; 56638494Sobrien show_time_host_and_name(lvl); /* mimic syslog header */ 567310490Scy __IGNORE(fwrite(msg, ptr - msg, 1, logfp)); 56838494Sobrien fflush(logfp); 56938494Sobrien break; 57038494Sobrien 57138494Sobrien case 1: /* item printed once, if same, don't repeat */ 57238494Sobrien if (STREQ(last_msg, msg)) { 57338494Sobrien last_count++; 57438494Sobrien } else { /* last msg printed once, new one differs */ 57538494Sobrien /* last_count remains at 1 */ 576310490Scy if (strlcpy(last_msg, msg, sizeof(last_msg)) >= sizeof(last_msg)) /* don't use xstrlcpy here (recursive!) */ 577174294Sobrien fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); 57838494Sobrien last_lvl = lvl; 57938494Sobrien show_time_host_and_name(lvl); /* mimic syslog header */ 580310490Scy __IGNORE(fwrite(msg, ptr - msg, 1, logfp)); 58138494Sobrien fflush(logfp); 58238494Sobrien } 58338494Sobrien break; 58438494Sobrien 58538494Sobrien case 100: 58638494Sobrien /* 58738494Sobrien * Don't allow repetitions longer than 100, so you can see when something 58838494Sobrien * cycles like crazy. 58938494Sobrien */ 59038494Sobrien show_time_host_and_name(last_lvl); 591174294Sobrien xsnprintf(last_msg, sizeof(last_msg), 592174294Sobrien "last message repeated %d times\n", last_count); 593310490Scy __IGNORE(fwrite(last_msg, strlen(last_msg), 1, logfp)); 59438494Sobrien fflush(logfp); 59538494Sobrien last_count = 0; /* start from scratch */ 59638494Sobrien break; 59738494Sobrien 59838494Sobrien default: /* item repeated multiple times */ 59938494Sobrien if (STREQ(last_msg, msg)) { 60038494Sobrien last_count++; 60138494Sobrien } else { /* last msg repeated+skipped, new one differs */ 60238494Sobrien show_time_host_and_name(last_lvl); 603174294Sobrien xsnprintf(last_msg, sizeof(last_msg), 604174294Sobrien "last message repeated %d times\n", last_count); 605310490Scy __IGNORE(fwrite(last_msg, strlen(last_msg), 1, logfp)); 606174294Sobrien if (strlcpy(last_msg, msg, 1024) >= 1024) /* don't use xstrlcpy here (recursive!) */ 607174294Sobrien fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg); 60838494Sobrien last_count = 1; 60938494Sobrien last_lvl = lvl; 61038494Sobrien show_time_host_and_name(lvl); /* mimic syslog header */ 611310490Scy __IGNORE(fwrite(msg, ptr - msg, 1, logfp)); 61238494Sobrien fflush(logfp); 61338494Sobrien } 61438494Sobrien break; 61538494Sobrien } 61638494Sobrien 61738494Sobrien} 61838494Sobrien 61938494Sobrien 62038494Sobrien/* 62138494Sobrien * Display current debug options 62238494Sobrien */ 62338494Sobrienvoid 62438494Sobrienshow_opts(int ch, struct opt_tab *opts) 62538494Sobrien{ 62638494Sobrien int i; 62738494Sobrien int s = '{'; 62838494Sobrien 62938494Sobrien fprintf(stderr, "\t[-%c {no}", ch); 63038494Sobrien for (i = 0; opts[i].opt; i++) { 63138494Sobrien fprintf(stderr, "%c%s", s, opts[i].opt); 63238494Sobrien s = ','; 63338494Sobrien } 63438494Sobrien fputs("}]\n", stderr); 63538494Sobrien} 63638494Sobrien 63738494Sobrien 63838494Sobrienint 639310490Scycmdoption(char *s, struct opt_tab *optb, u_int *flags) 64038494Sobrien{ 64138494Sobrien char *p = s; 64238494Sobrien int errs = 0; 64338494Sobrien 64438494Sobrien while (p && *p) { 64538494Sobrien int neg; 64638494Sobrien char *opt; 647310490Scy struct opt_tab *dp, *dpn = NULL; 64838494Sobrien 64938494Sobrien s = p; 65038494Sobrien p = strchr(p, ','); 65138494Sobrien if (p) 65238494Sobrien *p = '\0'; 65338494Sobrien 65438494Sobrien /* check for "no" prefix to options */ 65538494Sobrien if (s[0] == 'n' && s[1] == 'o') { 65638494Sobrien opt = s + 2; 65738494Sobrien neg = 1; 65838494Sobrien } else { 65938494Sobrien opt = s; 66038494Sobrien neg = 0; 66138494Sobrien } 66238494Sobrien 66338494Sobrien /* 66438494Sobrien * Scan the array of debug options to find the 66538494Sobrien * corresponding flag value. If it is found 66638494Sobrien * then set (or clear) the flag (depending on 66738494Sobrien * whether the option was prefixed with "no"). 66838494Sobrien */ 66938494Sobrien for (dp = optb; dp->opt; dp++) { 67038494Sobrien if (STREQ(opt, dp->opt)) 67138494Sobrien break; 67238494Sobrien if (opt != s && !dpn && STREQ(s, dp->opt)) 67338494Sobrien dpn = dp; 67438494Sobrien } 67538494Sobrien 67638494Sobrien if (dp->opt || dpn) { 67738494Sobrien if (!dp->opt) { 67838494Sobrien dp = dpn; 67938494Sobrien neg = !neg; 68038494Sobrien } 68138494Sobrien if (neg) 68238494Sobrien *flags &= ~dp->flag; 68338494Sobrien else 68438494Sobrien *flags |= dp->flag; 68538494Sobrien } else { 68638494Sobrien /* 68738494Sobrien * This will log to stderr when parsing the command line 68838494Sobrien * since any -l option will not yet have taken effect. 68938494Sobrien */ 690310490Scy plog(XLOG_ERROR, "option \"%s\" not recognized", s); 69138494Sobrien errs++; 69238494Sobrien } 69338494Sobrien 69438494Sobrien /* 69538494Sobrien * Put the comma back 69638494Sobrien */ 69738494Sobrien if (p) 69838494Sobrien *p++ = ','; 69938494Sobrien } 70038494Sobrien 70138494Sobrien return errs; 70238494Sobrien} 70338494Sobrien 70438494Sobrien 70538494Sobrien/* 70638494Sobrien * Switch on/off logging options 70738494Sobrien */ 70838494Sobrienint 70938494Sobrienswitch_option(char *opt) 71038494Sobrien{ 711310490Scy u_int xl = xlog_level; 71238494Sobrien int rc = cmdoption(opt, xlog_opt, &xl); 71338494Sobrien 714310490Scy if (rc) /* if got any error, don't update flags */ 715310490Scy return EINVAL; 716310490Scy 717310490Scy /* 718310490Scy * Don't allow "mandatory" flags to be turned off, because 719310490Scy * we must always be able to report on flag re/setting errors. 720310490Scy */ 721310490Scy if ((xl & XLOG_MANDATORY) != XLOG_MANDATORY) { 722310490Scy plog(XLOG_ERROR, "cannot turn off mandatory logging options"); 723310490Scy xl |= XLOG_MANDATORY; 72438494Sobrien } 725310490Scy if (xlog_level != xl) 726310490Scy xlog_level = xl; /* set new flags */ 72738494Sobrien return rc; 72838494Sobrien} 72938494Sobrien 730174294Sobrien 73151292Sobrien#ifdef LOG_DAEMON 73238494Sobrien/* 73338494Sobrien * get syslog facility to use. 73438494Sobrien * logfile can be "syslog", "syslog:daemon", "syslog:local7", etc. 73538494Sobrien */ 73638494Sobrienstatic int 73738494Sobrienget_syslog_facility(const char *logfile) 73838494Sobrien{ 73938494Sobrien char *facstr; 74038494Sobrien 74138494Sobrien /* parse facility string */ 74238494Sobrien facstr = strchr(logfile, ':'); 74338494Sobrien if (!facstr) /* log file was "syslog" */ 74438494Sobrien return LOG_DAEMON; 74538494Sobrien facstr++; 74638494Sobrien if (!facstr || facstr[0] == '\0') { /* log file was "syslog:" */ 74738494Sobrien plog(XLOG_WARNING, "null syslog facility, using LOG_DAEMON"); 74838494Sobrien return LOG_DAEMON; 74938494Sobrien } 75038494Sobrien 75138494Sobrien#ifdef LOG_KERN 75238494Sobrien if (STREQ(facstr, "kern")) 75338494Sobrien return LOG_KERN; 75438494Sobrien#endif /* not LOG_KERN */ 75538494Sobrien#ifdef LOG_USER 75638494Sobrien if (STREQ(facstr, "user")) 75738494Sobrien return LOG_USER; 75838494Sobrien#endif /* not LOG_USER */ 75938494Sobrien#ifdef LOG_MAIL 76038494Sobrien if (STREQ(facstr, "mail")) 76138494Sobrien return LOG_MAIL; 76238494Sobrien#endif /* not LOG_MAIL */ 76351292Sobrien 76438494Sobrien if (STREQ(facstr, "daemon")) 76538494Sobrien return LOG_DAEMON; 76651292Sobrien 76738494Sobrien#ifdef LOG_AUTH 76838494Sobrien if (STREQ(facstr, "auth")) 76938494Sobrien return LOG_AUTH; 77038494Sobrien#endif /* not LOG_AUTH */ 77138494Sobrien#ifdef LOG_SYSLOG 77238494Sobrien if (STREQ(facstr, "syslog")) 77338494Sobrien return LOG_SYSLOG; 77438494Sobrien#endif /* not LOG_SYSLOG */ 77538494Sobrien#ifdef LOG_LPR 77638494Sobrien if (STREQ(facstr, "lpr")) 77738494Sobrien return LOG_LPR; 77838494Sobrien#endif /* not LOG_LPR */ 77938494Sobrien#ifdef LOG_NEWS 78038494Sobrien if (STREQ(facstr, "news")) 78138494Sobrien return LOG_NEWS; 78238494Sobrien#endif /* not LOG_NEWS */ 78338494Sobrien#ifdef LOG_UUCP 78438494Sobrien if (STREQ(facstr, "uucp")) 78538494Sobrien return LOG_UUCP; 78638494Sobrien#endif /* not LOG_UUCP */ 78738494Sobrien#ifdef LOG_CRON 78838494Sobrien if (STREQ(facstr, "cron")) 78938494Sobrien return LOG_CRON; 79038494Sobrien#endif /* not LOG_CRON */ 79138494Sobrien#ifdef LOG_LOCAL0 79238494Sobrien if (STREQ(facstr, "local0")) 79338494Sobrien return LOG_LOCAL0; 79438494Sobrien#endif /* not LOG_LOCAL0 */ 79538494Sobrien#ifdef LOG_LOCAL1 79638494Sobrien if (STREQ(facstr, "local1")) 79738494Sobrien return LOG_LOCAL1; 79838494Sobrien#endif /* not LOG_LOCAL1 */ 79938494Sobrien#ifdef LOG_LOCAL2 80038494Sobrien if (STREQ(facstr, "local2")) 80138494Sobrien return LOG_LOCAL2; 80238494Sobrien#endif /* not LOG_LOCAL2 */ 80338494Sobrien#ifdef LOG_LOCAL3 80438494Sobrien if (STREQ(facstr, "local3")) 80538494Sobrien return LOG_LOCAL3; 80638494Sobrien#endif /* not LOG_LOCAL3 */ 80738494Sobrien#ifdef LOG_LOCAL4 80838494Sobrien if (STREQ(facstr, "local4")) 80938494Sobrien return LOG_LOCAL4; 81038494Sobrien#endif /* not LOG_LOCAL4 */ 81138494Sobrien#ifdef LOG_LOCAL5 81238494Sobrien if (STREQ(facstr, "local5")) 81338494Sobrien return LOG_LOCAL5; 81438494Sobrien#endif /* not LOG_LOCAL5 */ 81538494Sobrien#ifdef LOG_LOCAL6 81638494Sobrien if (STREQ(facstr, "local6")) 81738494Sobrien return LOG_LOCAL6; 81838494Sobrien#endif /* not LOG_LOCAL6 */ 81938494Sobrien#ifdef LOG_LOCAL7 82038494Sobrien if (STREQ(facstr, "local7")) 82138494Sobrien return LOG_LOCAL7; 82238494Sobrien#endif /* not LOG_LOCAL7 */ 82338494Sobrien 82438494Sobrien /* didn't match anything else */ 82538494Sobrien plog(XLOG_WARNING, "unknown syslog facility \"%s\", using LOG_DAEMON", facstr); 82638494Sobrien return LOG_DAEMON; 82738494Sobrien} 82851292Sobrien#endif /* not LOG_DAEMON */ 82938494Sobrien 83038494Sobrien 83138494Sobrien/* 83238494Sobrien * Change current logfile 83338494Sobrien */ 83438494Sobrienint 835174294Sobrienswitch_to_logfile(char *logfile, int old_umask, int truncate_log) 83638494Sobrien{ 83738494Sobrien FILE *new_logfp = stderr; 83838494Sobrien 83938494Sobrien if (logfile) { 84038494Sobrien#ifdef HAVE_SYSLOG 84138494Sobrien syslogging = 0; 84238494Sobrien#endif /* HAVE_SYSLOG */ 84338494Sobrien 84438494Sobrien if (STREQ(logfile, "/dev/stderr")) 84538494Sobrien new_logfp = stderr; 84638494Sobrien else if (NSTREQ(logfile, "syslog", strlen("syslog"))) { 84738494Sobrien 84838494Sobrien#ifdef HAVE_SYSLOG 84938494Sobrien syslogging = 1; 85038494Sobrien new_logfp = stderr; 85142629Sobrien openlog(am_get_progname(), 85238494Sobrien LOG_PID 85338494Sobrien# ifdef LOG_NOWAIT 85438494Sobrien | LOG_NOWAIT 85538494Sobrien# endif /* LOG_NOWAIT */ 85638494Sobrien# ifdef LOG_DAEMON 85738494Sobrien , get_syslog_facility(logfile) 85838494Sobrien# endif /* LOG_DAEMON */ 85938494Sobrien ); 86038494Sobrien#else /* not HAVE_SYSLOG */ 86138494Sobrien plog(XLOG_WARNING, "syslog option not supported, logging unchanged"); 86238494Sobrien#endif /* not HAVE_SYSLOG */ 86338494Sobrien 864174294Sobrien } else { /* regular log file */ 86542629Sobrien (void) umask(old_umask); 866174294Sobrien if (truncate_log) 867310490Scy __IGNORE(truncate(logfile, 0)); 86838494Sobrien new_logfp = fopen(logfile, "a"); 86938494Sobrien umask(0); 87038494Sobrien } 87138494Sobrien } 87238494Sobrien 87338494Sobrien /* 87438494Sobrien * If we couldn't open a new file, then continue using the old. 87538494Sobrien */ 87638494Sobrien if (!new_logfp && logfile) { 87738494Sobrien plog(XLOG_USER, "%s: Can't open logfile: %m", logfile); 87838494Sobrien return 1; 87938494Sobrien } 88038494Sobrien 88138494Sobrien /* 88238494Sobrien * Close the previous file 88338494Sobrien */ 88438494Sobrien if (logfp && logfp != stderr) 88538494Sobrien (void) fclose(logfp); 88638494Sobrien logfp = new_logfp; 88738494Sobrien 888119679Smbr if (logfile) 889119679Smbr plog(XLOG_INFO, "switched to logfile \"%s\"", logfile); 890119679Smbr else 891119679Smbr plog(XLOG_INFO, "no logfile defined; using stderr"); 892119679Smbr 89338494Sobrien return 0; 89438494Sobrien} 89538494Sobrien 89638494Sobrien 89738494Sobrienvoid 89838494Sobrienunregister_amq(void) 89938494Sobrien{ 900310490Scy 901310490Scy if (amuDebug(D_AMQ)) { 90238494Sobrien /* find which instance of amd to unregister */ 903174294Sobrien u_long amd_prognum = get_amd_program_number(); 904174294Sobrien 905174294Sobrien if (pmap_unset(amd_prognum, AMQ_VERSION) != 1) 906174294Sobrien dlog("failed to de-register Amd program %lu, version %lu", 907174294Sobrien amd_prognum, AMQ_VERSION); 908174294Sobrien } 90938494Sobrien} 91038494Sobrien 91138494Sobrien 91238494Sobrienvoid 91338494Sobriengoing_down(int rc) 91438494Sobrien{ 91538494Sobrien if (foreground) { 91638494Sobrien if (amd_state != Start) { 91738494Sobrien if (amd_state != Done) 91838494Sobrien return; 91938494Sobrien unregister_amq(); 92038494Sobrien } 92138494Sobrien } 922174294Sobrien 923174294Sobrien#ifdef MOUNT_TABLE_ON_FILE 924174294Sobrien /* 925174294Sobrien * Call unlock_mntlist to free any important resources such as an on-disk 926174294Sobrien * lock file (/etc/mtab~). 927174294Sobrien */ 928174294Sobrien unlock_mntlist(); 929174294Sobrien#endif /* MOUNT_TABLE_ON_FILE */ 930174294Sobrien 93138494Sobrien if (foreground) { 93238494Sobrien plog(XLOG_INFO, "Finishing with status %d", rc); 93338494Sobrien } else { 93438494Sobrien dlog("background process exiting with status %d", rc); 93538494Sobrien } 936174294Sobrien /* bye bye... */ 93738494Sobrien exit(rc); 93838494Sobrien} 93938494Sobrien 94038494Sobrien 94138494Sobrien/* return the rpc program number under which amd was used */ 942310490Scyu_long 94338494Sobrienget_amd_program_number(void) 94438494Sobrien{ 94538494Sobrien return amd_program_number; 94638494Sobrien} 94738494Sobrien 94838494Sobrien 94938494Sobrien/* set the rpc program number used for amd */ 95038494Sobrienvoid 951310490Scyset_amd_program_number(u_long program) 95238494Sobrien{ 95338494Sobrien amd_program_number = program; 95438494Sobrien} 95538494Sobrien 95638494Sobrien 95738494Sobrien/* 95838494Sobrien * Release the controlling tty of the process pid. 95938494Sobrien * 96038494Sobrien * Algorithm: try these in order, if available, until one of them 96138494Sobrien * succeeds: setsid(), ioctl(fd, TIOCNOTTY, 0). 96238494Sobrien * Do not use setpgid(): on some OSs it may release the controlling tty, 96338494Sobrien * even if the man page does not mention it, but on other OSs it does not. 96438494Sobrien * Also avoid setpgrp(): it works on some systems, and on others it is 96538494Sobrien * identical to setpgid(). 96638494Sobrien */ 96738494Sobrienvoid 96838494Sobrienamu_release_controlling_tty(void) 96938494Sobrien{ 97038494Sobrien int fd; 97138494Sobrien 97282794Sobrien /* 97382794Sobrien * In daemon mode, leaving open file descriptors to terminals or pipes 97482794Sobrien * can be a really bad idea. 97582794Sobrien * Case in point: the redhat startup script calls us through their 'initlog' 976119679Smbr * program, which exits as soon as the original amd process exits. If, 977119679Smbr * at some point, a misbehaved library function decides to print something 978119679Smbr * to the screen, we get a SIGPIPE and die. 979119679Smbr * And guess what: NIS glibc functions will attempt to print to stderr 98082794Sobrien * "YPBINDPROC_DOMAIN: Domain not bound" if ypbind is running but can't find 98182794Sobrien * a ypserver. 98282794Sobrien * 98382794Sobrien * So we close all of our "terminal" filedescriptors, i.e. 0, 1 and 2, then 98482794Sobrien * reopen them as /dev/null. 98582794Sobrien * 98682794Sobrien * XXX We should also probably set the SIGPIPE handler to SIG_IGN. 98782794Sobrien */ 988174294Sobrien fd = open("/dev/null", O_RDWR); 989174294Sobrien if (fd < 0) { 990174294Sobrien plog(XLOG_WARNING, "Could not open /dev/null for rw: %m"); 991174294Sobrien } else { 992174294Sobrien fflush(stdin); close(0); dup2(fd, 0); 993174294Sobrien fflush(stdout); close(1); dup2(fd, 1); 994174294Sobrien fflush(stderr); close(2); dup2(fd, 2); 995174294Sobrien close(fd); 996174294Sobrien } 99782794Sobrien 998119679Smbr#ifdef HAVE_SETSID 999119679Smbr /* XXX: one day maybe use vhangup(2) */ 1000119679Smbr if (setsid() < 0) { 1001119679Smbr plog(XLOG_WARNING, "Could not release controlling tty using setsid(): %m"); 1002119679Smbr } else { 1003119679Smbr plog(XLOG_INFO, "released controlling tty using setsid()"); 1004119679Smbr return; 1005119679Smbr } 1006119679Smbr#endif /* HAVE_SETSID */ 1007119679Smbr 100838494Sobrien#ifdef TIOCNOTTY 100938494Sobrien fd = open("/dev/tty", O_RDWR); 101038494Sobrien if (fd < 0) { 101138494Sobrien /* not an error if already no controlling tty */ 101238494Sobrien if (errno != ENXIO) 101338494Sobrien plog(XLOG_WARNING, "Could not open controlling tty: %m"); 101438494Sobrien } else { 101538494Sobrien if (ioctl(fd, TIOCNOTTY, 0) < 0 && errno != ENOTTY) 101638494Sobrien plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m"); 101738494Sobrien else 101838494Sobrien plog(XLOG_INFO, "released controlling tty using ioctl(TIOCNOTTY)"); 101938494Sobrien close(fd); 102038494Sobrien } 102138494Sobrien return; 1022310490Scy#else 1023310490Scy plog(XLOG_ERROR, "unable to release controlling tty"); 102438494Sobrien#endif /* not TIOCNOTTY */ 102538494Sobrien} 1026174294Sobrien 1027174294Sobrien 1028174294Sobrien/* setup a single signal handler */ 1029174294Sobrienvoid 1030174294Sobriensetup_sighandler(int signum, void (*handler)(int)) 1031174294Sobrien{ 1032174294Sobrien#ifdef HAVE_SIGACTION 1033174294Sobrien struct sigaction sa; 1034174294Sobrien memset(&sa, 0, sizeof(sa)); 1035174294Sobrien sa.sa_flags = 0; /* unnecessary */ 1036174294Sobrien sa.sa_handler = handler; 1037174294Sobrien sigemptyset(&(sa.sa_mask)); /* probably unnecessary too */ 1038174294Sobrien sigaddset(&(sa.sa_mask), signum); 1039174294Sobrien sigaction(signum, &sa, NULL); 1040174294Sobrien#else /* not HAVE_SIGACTION */ 1041174294Sobrien (void) signal(signum, handler); 1042174294Sobrien#endif /* not HAVE_SIGACTION */ 1043174294Sobrien} 1044174294Sobrien 1045174294Sobrien 1046174294Sobrien/* 1047174294Sobrien * Return current time in seconds. If passed a non-null argyument, then 1048174294Sobrien * fill it in with the current time in seconds and microseconds (useful 1049174294Sobrien * for mtime updates). 1050174294Sobrien */ 1051174294Sobrientime_t 1052174294Sobrienclocktime(nfstime *nt) 1053174294Sobrien{ 1054174294Sobrien static struct timeval now; /* keep last time, as default */ 1055174294Sobrien 1056174294Sobrien if (gettimeofday(&now, NULL) < 0) { 1057174294Sobrien plog(XLOG_ERROR, "clocktime: gettimeofday: %m"); 1058174294Sobrien /* hack: force time to have incremented by at least 1 second */ 1059174294Sobrien now.tv_sec++; 1060174294Sobrien } 1061174294Sobrien /* copy seconds and microseconds. may demote a long to an int */ 1062174294Sobrien if (nt) { 1063174294Sobrien nt->nt_seconds = (u_int) now.tv_sec; 1064174294Sobrien nt->nt_useconds = (u_int) now.tv_usec; 1065174294Sobrien } 1066174294Sobrien return (time_t) now.tv_sec; 1067174294Sobrien} 1068174294Sobrien 1069174294Sobrien 1070174294Sobrien/* 1071174294Sobrien * Make all the directories in the path. 1072174294Sobrien */ 1073174294Sobrienint 1074174294Sobrienmkdirs(char *path, int mode) 1075174294Sobrien{ 1076174294Sobrien /* 1077174294Sobrien * take a copy in case path is in readonly store 1078174294Sobrien */ 1079310490Scy char *p2 = xstrdup(path); 1080174294Sobrien char *sp = p2; 1081174294Sobrien struct stat stb; 1082174294Sobrien int error_so_far = 0; 1083174294Sobrien 1084174294Sobrien /* 1085174294Sobrien * Skip through the string make the directories. 1086174294Sobrien * Mostly ignore errors - the result is tested at the end. 1087174294Sobrien * 1088174294Sobrien * This assumes we are root so that we can do mkdir in a 1089174294Sobrien * mode 555 directory... 1090174294Sobrien */ 1091174294Sobrien while ((sp = strchr(sp + 1, '/'))) { 1092174294Sobrien *sp = '\0'; 1093174294Sobrien if (mkdir(p2, mode) < 0) { 1094174294Sobrien error_so_far = errno; 1095174294Sobrien } else { 1096174294Sobrien dlog("mkdir(%s)", p2); 1097174294Sobrien } 1098174294Sobrien *sp = '/'; 1099174294Sobrien } 1100174294Sobrien 1101174294Sobrien if (mkdir(p2, mode) < 0) { 1102174294Sobrien error_so_far = errno; 1103174294Sobrien } else { 1104174294Sobrien dlog("mkdir(%s)", p2); 1105174294Sobrien } 1106174294Sobrien 1107174294Sobrien XFREE(p2); 1108174294Sobrien 1109174294Sobrien return stat(path, &stb) == 0 && 1110174294Sobrien (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far; 1111174294Sobrien} 1112174294Sobrien 1113174294Sobrien 1114174294Sobrien/* 1115174294Sobrien * Remove as many directories in the path as possible. 1116174294Sobrien * Give up if the directory doesn't appear to have 1117174294Sobrien * been created by Amd (not mode dr-x) or an rmdir 1118174294Sobrien * fails for any reason. 1119174294Sobrien */ 1120174294Sobrienvoid 1121174294Sobrienrmdirs(char *dir) 1122174294Sobrien{ 1123310490Scy char *xdp = xstrdup(dir); 1124174294Sobrien char *dp; 1125174294Sobrien 1126174294Sobrien do { 1127174294Sobrien struct stat stb; 1128174294Sobrien /* 1129174294Sobrien * Try to find out whether this was 1130174294Sobrien * created by amd. Do this by checking 1131174294Sobrien * for owner write permission. 1132174294Sobrien */ 1133174294Sobrien if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) { 1134174294Sobrien if (rmdir(xdp) < 0) { 1135174294Sobrien if (errno != ENOTEMPTY && 1136174294Sobrien errno != EBUSY && 1137174294Sobrien errno != EEXIST && 1138174294Sobrien errno != EROFS && 1139174294Sobrien errno != EINVAL) 1140174294Sobrien plog(XLOG_ERROR, "rmdir(%s): %m", xdp); 1141174294Sobrien break; 1142174294Sobrien } else { 1143174294Sobrien dlog("rmdir(%s)", xdp); 1144174294Sobrien } 1145174294Sobrien } else { 1146174294Sobrien break; 1147174294Sobrien } 1148174294Sobrien 1149174294Sobrien dp = strrchr(xdp, '/'); 1150174294Sobrien if (dp) 1151174294Sobrien *dp = '\0'; 1152174294Sobrien } while (dp && dp > xdp); 1153174294Sobrien 1154174294Sobrien XFREE(xdp); 1155174294Sobrien} 1156310490Scy 1157310490Scy/* 1158310490Scy * Dup a string 1159310490Scy */ 1160310490Scychar * 1161310490Scyxstrdup(const char *s) 1162310490Scy{ 1163310490Scy size_t len = strlen(s); 1164310490Scy char *sp = xmalloc(len + 1); 1165310490Scy memcpy(sp, s, len + 1); 1166310490Scy return sp; 1167310490Scy} 1168