2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * File: am-utils/libamu/xutil.c
41 * Miscellaneous Utilities: Logging, TTY, timers, signals, RPC, memory, etc.
46 #endif /* HAVE_CONFIG_H */
51 * Logfp is the default logging device, and is initialized to stderr by
52 * default in dplog/plog below, and in
53 * amd/amfs_program.c:amfs_program_exec().
57 static char *am_progname = "unknown"; /* "amd" */
58 static char am_hostname[MAXHOSTNAMELEN] = "unknown"; /* Hostname */
59 pid_t am_mypid = -1; /* process ID */
60 serv_state amd_state; /* amd's state */
61 int foreground = 1; /* 1 == this is the top-level server */
62 u_int debug_flags = D_CONTROL; /* set regardless if compiled with debugging */
66 #endif /* HAVE_SYSLOG */
67 static u_int xlog_level = XLOG_DEFAULT;
68 static u_long amd_program_number = AMQ_PROGRAM;
71 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
73 static int orig_mem_bytes;
74 # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
75 #endif /* DEBUG_MEM */
77 /* forward definitions */
78 /* for GCC format string auditing */
79 static void real_plog(int lvl, const char *fmt, va_list vargs)
80 __attribute__((__format__(__printf__, 2, 0)));
85 * List of debug options.
87 struct opt_tab dbg_opt[] =
89 {"all", D_ALL}, /* All non-disruptive options */
90 {"defaults", D_DEFAULT}, /* Default options */
91 {"test", D_TEST}, /* Full debug - no daemon, no fork, no amq, local mtab */
92 {"amq", D_AMQ}, /* Register for AMQ program */
93 {"daemon", D_DAEMON}, /* Enter daemon mode */
94 {"fork", D_FORK}, /* Fork server (hlfsd only) */
95 {"full", D_FULL}, /* Program trace */
96 #ifdef HAVE_CLOCK_GETTIME
97 {"hrtime", D_HRTIME}, /* Print high resolution time stamps */
98 #endif /* HAVE_CLOCK_GETTIME */
99 {"info", D_INFO}, /* info service specific debugging (hesiod, nis, etc) */
100 {"mem", D_MEM}, /* Trace memory allocations */
101 {"mtab", D_MTAB}, /* Use local mtab file */
102 {"readdir", D_READDIR}, /* Check on browsable_dirs progress */
103 {"str", D_STR}, /* Debug string munging */
104 {"trace", D_TRACE}, /* Protocol trace */
105 {"xdrtrace", D_XDRTRACE}, /* Trace xdr routines */
111 * List of log options
113 struct opt_tab xlog_opt[] =
115 {"all", XLOG_ALL}, /* All messages */
116 {"defaults", XLOG_DEFAULT}, /* Default messages */
118 {"debug", XLOG_DEBUG}, /* Debug messages */
119 #endif /* DEBUG */ /* DEBUG */
120 {"error", XLOG_ERROR}, /* Non-fatal system errors */
121 {"fatal", XLOG_FATAL}, /* Fatal errors */
122 {"info", XLOG_INFO}, /* Information */
123 {"map", XLOG_MAP}, /* Map errors */
124 {"stats", XLOG_STATS}, /* Additional statistical information */
125 {"user", XLOG_USER}, /* Non-fatal user errors */
126 {"warn", XLOG_WARNING}, /* Warnings */
127 {"warning", XLOG_WARNING}, /* Warnings */
133 am_set_progname(char *pn)
140 am_get_progname(void)
147 am_set_hostname(char *hn)
149 xstrlcpy(am_hostname, hn, sizeof(am_hostname));
154 am_get_hostname(void)
171 return (long) (foreground ? am_mypid : getppid());
182 * Avoid malloc's which return NULL for malloc(0)
188 p = (voidp) malloc((unsigned) len);
191 plog(XLOG_DEBUG, "Allocated size %d; block %p", len, p);
195 plog(XLOG_ERROR, "Retrying memory allocation");
200 plog(XLOG_FATAL, "Out of memory");
209 /* like xmalloc, but zeros out the bytes */
213 voidp p = xmalloc(len);
222 xrealloc(voidp ptr, int len)
225 plog(XLOG_DEBUG, "Reallocated size %d; block %p", len, ptr);
231 ptr = (voidp) realloc(ptr, (unsigned) len);
233 ptr = (voidp) xmalloc((unsigned) len);
236 plog(XLOG_FATAL, "Out of memory in realloc");
246 dxfree(char *file, int line, voidp ptr)
249 plog(XLOG_DEBUG, "Free in %s:%d: block %p", file, line, ptr);
250 /* this is the only place that must NOT use XFREE()!!! */
252 ptr = NULL; /* paranoid */
256 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
260 struct mallinfo mi = mallinfo();
261 u_long uordbytes = mi.uordblks * 4096;
263 if (mem_bytes != uordbytes) {
264 if (orig_mem_bytes == 0)
265 mem_bytes = orig_mem_bytes = uordbytes;
267 fprintf(logfp, "%s[%ld]: ", am_get_progname(), (long) am_mypid);
268 if (mem_bytes < uordbytes) {
269 fprintf(logfp, "ALLOC: %ld bytes", uordbytes - mem_bytes);
271 fprintf(logfp, "FREE: %ld bytes", mem_bytes - uordbytes);
273 mem_bytes = uordbytes;
274 fprintf(logfp, ", making %d missing\n", mem_bytes - orig_mem_bytes);
279 # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
280 #endif /* DEBUG_MEM */
284 * Take a log format string and expand occurrences of %m
285 * with the current error code taken from errno. Make sure
286 * 'e' never gets longer than maxlen characters.
289 expand_error(const char *f, char *e, size_t maxlen)
297 for (p = f, q = e; len < maxlen && (*q = *p); len++, q++, p++) {
298 if (p[0] == '%' && p[1] == 'm') {
301 xstrlcpy(q, strerror(error), maxlen - len);
310 e[maxlen - 1] = '\0'; /* null terminate, to be sure */
316 * Output the time of day and hostname to the logfile
319 show_time_host_and_name(int lvl)
321 static time_t last_t = 0;
322 static char *last_ctime = NULL;
324 #if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG)
326 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */
327 char nsecs[11]; /* '.' + 9 digits + '\0' */
332 #if defined(HAVE_CLOCK_GETTIME) && defined(DEBUG)
334 * Some systems (AIX 4.3) seem to implement clock_gettime() as stub
337 if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
339 if (amuDebug(D_HRTIME))
340 xsnprintf(nsecs, sizeof(nsecs), ".%09ld", ts.tv_nsec);
343 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(DEBUG) */
347 last_ctime = ctime(&t);
380 fprintf(logfp, "%15.15s%s %s %s[%ld]/%s ",
381 last_ctime + 4, nsecs, am_get_hostname(),
390 * Switch on/off debug options
393 debug_option(char *opt)
395 u_int dl = debug_flags;
396 static int initialized_debug_flags = 0;
397 int rc = cmdoption(opt, dbg_opt, &dl);
399 if (rc) /* if got any error, don't update debug flags */
403 * If we already initialized the debugging flags once (via amd.conf), then
404 * don't allow "immutable" flags to be changed again (via amq -D), because
405 * they could mess Amd's state and only make sense to be set once when Amd
408 if (initialized_debug_flags &&
410 (dl & D_IMMUTABLE) != (debug_flags & D_IMMUTABLE)) {
411 plog(XLOG_ERROR, "cannot change immutable debug flags");
412 /* undo any attempted change to an immutable flag */
413 dl = (dl & ~D_IMMUTABLE) | (debug_flags & D_IMMUTABLE);
415 initialized_debug_flags = 1;
423 dplog(const char *fmt, ...)
425 #ifdef HAVE_SIGACTION
427 #else /* not HAVE_SIGACTION */
429 #endif /* not HAVE_SIGACTION */
432 #ifdef HAVE_SIGACTION
434 sigaddset(&chld, SIGCHLD);
435 #else /* not HAVE_SIGACTION */
436 mask = sigblock(sigmask(SIGCHLD));
437 #endif /* not HAVE_SIGACTION */
439 sigprocmask(SIG_BLOCK, &chld, &old);
441 logfp = stderr; /* initialize before possible first use */
444 real_plog(XLOG_DEBUG, fmt, ap);
447 #ifdef HAVE_SIGACTION
448 sigprocmask(SIG_SETMASK, &old, NULL);
449 #else /* not HAVE_SIGACTION */
450 mask = sigblock(sigmask(SIGCHLD));
451 #endif /* not HAVE_SIGACTION */
457 plog(int lvl, const char *fmt, ...)
459 #ifdef HAVE_SIGACTION
461 #else /* not HAVE_SIGACTION */
463 #endif /* not HAVE_SIGACTION */
466 #ifdef HAVE_SIGACTION
468 sigaddset(&chld, SIGCHLD);
469 sigprocmask(SIG_BLOCK, &chld, &old);
470 #else /* not HAVE_SIGACTION */
471 mask = sigblock(sigmask(SIGCHLD));
472 #endif /* not HAVE_SIGACTION */
475 logfp = stderr; /* initialize before possible first use */
478 real_plog(lvl, fmt, ap);
481 #ifdef HAVE_SIGACTION
482 sigprocmask(SIG_SETMASK, &old, NULL);
483 #else /* not HAVE_SIGACTION */
485 #endif /* not HAVE_SIGACTION */
490 real_plog(int lvl, const char *fmt, va_list vargs)
495 static char last_msg[1024];
496 static int last_count = 0, last_lvl = 0;
498 if (!(xlog_level & lvl))
502 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
504 # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
505 #endif /* DEBUG_MEM */
508 * Note: xvsnprintf() may call plog() if a truncation happened, but the
509 * latter has some code to break out of an infinite loop. See comment in
512 xvsnprintf(ptr, 1023, expand_error(fmt, efmt, 1024), vargs);
515 if (*(ptr-1) == '\n')
520 switch (lvl) { /* from mike <mcooper@usc.edu> */
549 syslog(lvl, "%s", msg);
552 #endif /* HAVE_SYSLOG */
558 * mimic syslog behavior: only write repeated strings if they differ
560 switch (last_count) {
561 case 0: /* never printed at all */
563 if (strlcpy(last_msg, msg, sizeof(last_msg)) >= sizeof(last_msg)) /* don't use xstrlcpy here (recursive!) */
564 fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg);
566 show_time_host_and_name(lvl); /* mimic syslog header */
567 __IGNORE(fwrite(msg, ptr - msg, 1, logfp));
571 case 1: /* item printed once, if same, don't repeat */
572 if (STREQ(last_msg, msg)) {
574 } else { /* last msg printed once, new one differs */
575 /* last_count remains at 1 */
576 if (strlcpy(last_msg, msg, sizeof(last_msg)) >= sizeof(last_msg)) /* don't use xstrlcpy here (recursive!) */
577 fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg);
579 show_time_host_and_name(lvl); /* mimic syslog header */
580 __IGNORE(fwrite(msg, ptr - msg, 1, logfp));
587 * Don't allow repetitions longer than 100, so you can see when something
590 show_time_host_and_name(last_lvl);
591 xsnprintf(last_msg, sizeof(last_msg),
592 "last message repeated %d times\n", last_count);
593 __IGNORE(fwrite(last_msg, strlen(last_msg), 1, logfp));
595 last_count = 0; /* start from scratch */
598 default: /* item repeated multiple times */
599 if (STREQ(last_msg, msg)) {
601 } else { /* last msg repeated+skipped, new one differs */
602 show_time_host_and_name(last_lvl);
603 xsnprintf(last_msg, sizeof(last_msg),
604 "last message repeated %d times\n", last_count);
605 __IGNORE(fwrite(last_msg, strlen(last_msg), 1, logfp));
606 if (strlcpy(last_msg, msg, 1024) >= 1024) /* don't use xstrlcpy here (recursive!) */
607 fprintf(stderr, "real_plog: string \"%s\" truncated to \"%s\"\n", last_msg, msg);
610 show_time_host_and_name(lvl); /* mimic syslog header */
611 __IGNORE(fwrite(msg, ptr - msg, 1, logfp));
621 * Display current debug options
624 show_opts(int ch, struct opt_tab *opts)
629 fprintf(stderr, "\t[-%c {no}", ch);
630 for (i = 0; opts[i].opt; i++) {
631 fprintf(stderr, "%c%s", s, opts[i].opt);
634 fputs("}]\n", stderr);
639 cmdoption(char *s, struct opt_tab *optb, u_int *flags)
647 struct opt_tab *dp, *dpn = NULL;
654 /* check for "no" prefix to options */
655 if (s[0] == 'n' && s[1] == 'o') {
664 * Scan the array of debug options to find the
665 * corresponding flag value. If it is found
666 * then set (or clear) the flag (depending on
667 * whether the option was prefixed with "no").
669 for (dp = optb; dp->opt; dp++) {
670 if (STREQ(opt, dp->opt))
672 if (opt != s && !dpn && STREQ(s, dp->opt))
676 if (dp->opt || dpn) {
687 * This will log to stderr when parsing the command line
688 * since any -l option will not yet have taken effect.
690 plog(XLOG_ERROR, "option \"%s\" not recognized", s);
706 * Switch on/off logging options
709 switch_option(char *opt)
711 u_int xl = xlog_level;
712 int rc = cmdoption(opt, xlog_opt, &xl);
714 if (rc) /* if got any error, don't update flags */
718 * Don't allow "mandatory" flags to be turned off, because
719 * we must always be able to report on flag re/setting errors.
721 if ((xl & XLOG_MANDATORY) != XLOG_MANDATORY) {
722 plog(XLOG_ERROR, "cannot turn off mandatory logging options");
723 xl |= XLOG_MANDATORY;
725 if (xlog_level != xl)
726 xlog_level = xl; /* set new flags */
733 * get syslog facility to use.
734 * logfile can be "syslog", "syslog:daemon", "syslog:local7", etc.
737 get_syslog_facility(const char *logfile)
741 /* parse facility string */
742 facstr = strchr(logfile, ':');
743 if (!facstr) /* log file was "syslog" */
746 if (!facstr || facstr[0] == '\0') { /* log file was "syslog:" */
747 plog(XLOG_WARNING, "null syslog facility, using LOG_DAEMON");
752 if (STREQ(facstr, "kern"))
754 #endif /* not LOG_KERN */
756 if (STREQ(facstr, "user"))
758 #endif /* not LOG_USER */
760 if (STREQ(facstr, "mail"))
762 #endif /* not LOG_MAIL */
764 if (STREQ(facstr, "daemon"))
768 if (STREQ(facstr, "auth"))
770 #endif /* not LOG_AUTH */
772 if (STREQ(facstr, "syslog"))
774 #endif /* not LOG_SYSLOG */
776 if (STREQ(facstr, "lpr"))
778 #endif /* not LOG_LPR */
780 if (STREQ(facstr, "news"))
782 #endif /* not LOG_NEWS */
784 if (STREQ(facstr, "uucp"))
786 #endif /* not LOG_UUCP */
788 if (STREQ(facstr, "cron"))
790 #endif /* not LOG_CRON */
792 if (STREQ(facstr, "local0"))
794 #endif /* not LOG_LOCAL0 */
796 if (STREQ(facstr, "local1"))
798 #endif /* not LOG_LOCAL1 */
800 if (STREQ(facstr, "local2"))
802 #endif /* not LOG_LOCAL2 */
804 if (STREQ(facstr, "local3"))
806 #endif /* not LOG_LOCAL3 */
808 if (STREQ(facstr, "local4"))
810 #endif /* not LOG_LOCAL4 */
812 if (STREQ(facstr, "local5"))
814 #endif /* not LOG_LOCAL5 */
816 if (STREQ(facstr, "local6"))
818 #endif /* not LOG_LOCAL6 */
820 if (STREQ(facstr, "local7"))
822 #endif /* not LOG_LOCAL7 */
824 /* didn't match anything else */
825 plog(XLOG_WARNING, "unknown syslog facility \"%s\", using LOG_DAEMON", facstr);
828 #endif /* not LOG_DAEMON */
832 * Change current logfile
835 switch_to_logfile(char *logfile, int old_umask, int truncate_log)
837 FILE *new_logfp = stderr;
842 #endif /* HAVE_SYSLOG */
844 if (STREQ(logfile, "/dev/stderr"))
846 else if (NSTREQ(logfile, "syslog", strlen("syslog"))) {
851 openlog(am_get_progname(),
855 # endif /* LOG_NOWAIT */
857 , get_syslog_facility(logfile)
858 # endif /* LOG_DAEMON */
860 #else /* not HAVE_SYSLOG */
861 plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
862 #endif /* not HAVE_SYSLOG */
864 } else { /* regular log file */
865 (void) umask(old_umask);
867 __IGNORE(truncate(logfile, 0));
868 new_logfp = fopen(logfile, "a");
874 * If we couldn't open a new file, then continue using the old.
876 if (!new_logfp && logfile) {
877 plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
882 * Close the previous file
884 if (logfp && logfp != stderr)
885 (void) fclose(logfp);
889 plog(XLOG_INFO, "switched to logfile \"%s\"", logfile);
891 plog(XLOG_INFO, "no logfile defined; using stderr");
901 if (amuDebug(D_AMQ)) {
902 /* find which instance of amd to unregister */
903 u_long amd_prognum = get_amd_program_number();
905 if (pmap_unset(amd_prognum, AMQ_VERSION) != 1)
906 dlog("failed to de-register Amd program %lu, version %lu",
907 amd_prognum, AMQ_VERSION);
916 if (amd_state != Start) {
917 if (amd_state != Done)
923 #ifdef MOUNT_TABLE_ON_FILE
925 * Call unlock_mntlist to free any important resources such as an on-disk
926 * lock file (/etc/mtab~).
929 #endif /* MOUNT_TABLE_ON_FILE */
932 plog(XLOG_INFO, "Finishing with status %d", rc);
934 dlog("background process exiting with status %d", rc);
941 /* return the rpc program number under which amd was used */
943 get_amd_program_number(void)
945 return amd_program_number;
949 /* set the rpc program number used for amd */
951 set_amd_program_number(u_long program)
953 amd_program_number = program;
958 * Release the controlling tty of the process pid.
960 * Algorithm: try these in order, if available, until one of them
961 * succeeds: setsid(), ioctl(fd, TIOCNOTTY, 0).
962 * Do not use setpgid(): on some OSs it may release the controlling tty,
963 * even if the man page does not mention it, but on other OSs it does not.
964 * Also avoid setpgrp(): it works on some systems, and on others it is
965 * identical to setpgid().
968 amu_release_controlling_tty(void)
973 * In daemon mode, leaving open file descriptors to terminals or pipes
974 * can be a really bad idea.
975 * Case in point: the redhat startup script calls us through their 'initlog'
976 * program, which exits as soon as the original amd process exits. If,
977 * at some point, a misbehaved library function decides to print something
978 * to the screen, we get a SIGPIPE and die.
979 * And guess what: NIS glibc functions will attempt to print to stderr
980 * "YPBINDPROC_DOMAIN: Domain not bound" if ypbind is running but can't find
983 * So we close all of our "terminal" filedescriptors, i.e. 0, 1 and 2, then
984 * reopen them as /dev/null.
986 * XXX We should also probably set the SIGPIPE handler to SIG_IGN.
988 fd = open("/dev/null", O_RDWR);
990 plog(XLOG_WARNING, "Could not open /dev/null for rw: %m");
992 fflush(stdin); close(0); dup2(fd, 0);
993 fflush(stdout); close(1); dup2(fd, 1);
994 fflush(stderr); close(2); dup2(fd, 2);
999 /* XXX: one day maybe use vhangup(2) */
1001 plog(XLOG_WARNING, "Could not release controlling tty using setsid(): %m");
1003 plog(XLOG_INFO, "released controlling tty using setsid()");
1006 #endif /* HAVE_SETSID */
1009 fd = open("/dev/tty", O_RDWR);
1011 /* not an error if already no controlling tty */
1013 plog(XLOG_WARNING, "Could not open controlling tty: %m");
1015 if (ioctl(fd, TIOCNOTTY, 0) < 0 && errno != ENOTTY)
1016 plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
1018 plog(XLOG_INFO, "released controlling tty using ioctl(TIOCNOTTY)");
1023 plog(XLOG_ERROR, "unable to release controlling tty");
1024 #endif /* not TIOCNOTTY */
1028 /* setup a single signal handler */
1030 setup_sighandler(int signum, void (*handler)(int))
1032 #ifdef HAVE_SIGACTION
1033 struct sigaction sa;
1034 memset(&sa, 0, sizeof(sa));
1035 sa.sa_flags = 0; /* unnecessary */
1036 sa.sa_handler = handler;
1037 sigemptyset(&(sa.sa_mask)); /* probably unnecessary too */
1038 sigaddset(&(sa.sa_mask), signum);
1039 sigaction(signum, &sa, NULL);
1040 #else /* not HAVE_SIGACTION */
1041 (void) signal(signum, handler);
1042 #endif /* not HAVE_SIGACTION */
1047 * Return current time in seconds. If passed a non-null argyument, then
1048 * fill it in with the current time in seconds and microseconds (useful
1049 * for mtime updates).
1052 clocktime(nfstime *nt)
1054 static struct timeval now; /* keep last time, as default */
1056 if (gettimeofday(&now, NULL) < 0) {
1057 plog(XLOG_ERROR, "clocktime: gettimeofday: %m");
1058 /* hack: force time to have incremented by at least 1 second */
1061 /* copy seconds and microseconds. may demote a long to an int */
1063 nt->nt_seconds = (u_int) now.tv_sec;
1064 nt->nt_useconds = (u_int) now.tv_usec;
1066 return (time_t) now.tv_sec;
1071 * Make all the directories in the path.
1074 mkdirs(char *path, int mode)
1077 * take a copy in case path is in readonly store
1079 char *p2 = xstrdup(path);
1082 int error_so_far = 0;
1085 * Skip through the string make the directories.
1086 * Mostly ignore errors - the result is tested at the end.
1088 * This assumes we are root so that we can do mkdir in a
1089 * mode 555 directory...
1091 while ((sp = strchr(sp + 1, '/'))) {
1093 if (mkdir(p2, mode) < 0) {
1094 error_so_far = errno;
1096 dlog("mkdir(%s)", p2);
1101 if (mkdir(p2, mode) < 0) {
1102 error_so_far = errno;
1104 dlog("mkdir(%s)", p2);
1109 return stat(path, &stb) == 0 &&
1110 (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far;
1115 * Remove as many directories in the path as possible.
1116 * Give up if the directory doesn't appear to have
1117 * been created by Amd (not mode dr-x) or an rmdir
1118 * fails for any reason.
1123 char *xdp = xstrdup(dir);
1129 * Try to find out whether this was
1130 * created by amd. Do this by checking
1131 * for owner write permission.
1133 if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) {
1134 if (rmdir(xdp) < 0) {
1135 if (errno != ENOTEMPTY &&
1140 plog(XLOG_ERROR, "rmdir(%s): %m", xdp);
1143 dlog("rmdir(%s)", xdp);
1149 dp = strrchr(xdp, '/');
1152 } while (dp && dp > xdp);
1161 xstrdup(const char *s)
1163 size_t len = strlen(s);
1164 char *sp = xmalloc(len + 1);
1165 memcpy(sp, s, len + 1);