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