130e13732Spendry /*
230e13732Spendry * Copyright (c) 1990 Jan-Simon Pendry
330e13732Spendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4*4092c5ccSbostic * Copyright (c) 1990, 1993
5*4092c5ccSbostic * The Regents of the University of California. All rights reserved.
630e13732Spendry *
730e13732Spendry * This code is derived from software contributed to Berkeley by
830e13732Spendry * Jan-Simon Pendry at Imperial College, London.
930e13732Spendry *
108a89c22cSpendry * %sccs.include.redist.c%
1130e13732Spendry *
12*4092c5ccSbostic * @(#)xutil.c 8.1 (Berkeley) 06/06/93
13c626267eSpendry *
1410042f30Spendry * $Id: xutil.c,v 5.2.2.3 1992/03/07 10:36:09 jsp Exp $
15c626267eSpendry *
1630e13732Spendry */
1730e13732Spendry
1830e13732Spendry #include "config.h"
1930e13732Spendry #ifdef HAS_SYSLOG
2030e13732Spendry #include <syslog.h>
2130e13732Spendry #endif /* HAS_SYSLOG */
2218436490Spendry #ifdef HAS_STRERROR
2318436490Spendry #include <string.h>
2418436490Spendry #endif
2530e13732Spendry
2630e13732Spendry FILE *logfp = stderr; /* Log errors to stderr initially */
2730e13732Spendry #ifdef HAS_SYSLOG
2830e13732Spendry int syslogging;
2930e13732Spendry #endif /* HAS_SYSLOG */
3030e13732Spendry int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS;
3130e13732Spendry int xlog_level_init = ~0;
3230e13732Spendry
3330e13732Spendry /*
3430e13732Spendry * List of log options
3530e13732Spendry */
3630e13732Spendry struct opt_tab xlog_opt[] = {
3730e13732Spendry { "all", XLOG_ALL }, /* All messages */
3830e13732Spendry #ifdef DEBUG
3930e13732Spendry { "debug", XLOG_DEBUG }, /* Debug messages */
4030e13732Spendry #endif /* DEBUG */
4130e13732Spendry { "error", XLOG_ERROR }, /* Non-fatal system errors */
4230e13732Spendry { "fatal", XLOG_FATAL }, /* Fatal errors */
4330e13732Spendry { "info", XLOG_INFO }, /* Information */
4430e13732Spendry { "map", XLOG_MAP }, /* Map errors */
4530e13732Spendry { "stats", XLOG_STATS }, /* Additional statistical information */
4630e13732Spendry { "user", XLOG_USER }, /* Non-fatal user errors */
4730e13732Spendry { "warn", XLOG_WARNING }, /* Warnings */
4830e13732Spendry { "warning", XLOG_WARNING }, /* Warnings */
4930e13732Spendry { 0, 0 }
5030e13732Spendry };
5130e13732Spendry
xmalloc(len)5230e13732Spendry voidp xmalloc(len)
5330e13732Spendry int len;
5430e13732Spendry {
5530e13732Spendry voidp p;
5630e13732Spendry int retries = 600;
5730e13732Spendry
5810042f30Spendry /*
5910042f30Spendry * Avoid malloc's which return NULL for malloc(0)
6010042f30Spendry */
6110042f30Spendry if (len == 0)
6210042f30Spendry len = 1;
6310042f30Spendry
6430e13732Spendry do {
6530e13732Spendry p = (voidp) malloc((unsigned) len);
6630e13732Spendry if (p) {
6730e13732Spendry #if defined(DEBUG) && defined(DEBUG_MEM)
6830e13732Spendry Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
6930e13732Spendry #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
7030e13732Spendry return p;
7130e13732Spendry }
7230e13732Spendry if (retries > 0) {
7330e13732Spendry plog(XLOG_ERROR, "Retrying memory allocation");
7430e13732Spendry sleep(1);
7530e13732Spendry }
7630e13732Spendry } while (--retries);
7730e13732Spendry
7830e13732Spendry plog(XLOG_FATAL, "Out of memory");
7930e13732Spendry going_down(1);
8030e13732Spendry
8130e13732Spendry abort();
8230e13732Spendry
8330e13732Spendry return 0;
8430e13732Spendry }
8530e13732Spendry
xrealloc(ptr,len)8630e13732Spendry voidp xrealloc(ptr, len)
8730e13732Spendry voidp ptr;
8830e13732Spendry int len;
8930e13732Spendry {
9030e13732Spendry #if defined(DEBUG) && defined(DEBUG_MEM)
9130e13732Spendry Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
9230e13732Spendry #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
9330e13732Spendry
9410042f30Spendry if (len == 0)
9510042f30Spendry len = 1;
9610042f30Spendry
9730e13732Spendry if (ptr)
9830e13732Spendry ptr = (voidp) realloc(ptr, (unsigned) len);
9930e13732Spendry else
10030e13732Spendry ptr = (voidp) xmalloc((unsigned) len);
10130e13732Spendry
10230e13732Spendry if (!ptr) {
10330e13732Spendry plog(XLOG_FATAL, "Out of memory in realloc");
10430e13732Spendry going_down(1);
10530e13732Spendry abort();
10630e13732Spendry }
10730e13732Spendry return ptr;
10830e13732Spendry }
10930e13732Spendry
11030e13732Spendry #if defined(DEBUG) && defined(DEBUG_MEM)
xfree(f,l,p)11130e13732Spendry xfree(f, l, p)
11230e13732Spendry char *f;
11330e13732Spendry int l;
11430e13732Spendry voidp p;
11530e13732Spendry {
11630e13732Spendry Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p);
11730e13732Spendry #undef free
11830e13732Spendry free(p);
11930e13732Spendry }
12030e13732Spendry #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
12130e13732Spendry #ifdef DEBUG_MEM
12230e13732Spendry static int mem_bytes;
12330e13732Spendry static int orig_mem_bytes;
checkup_mem(P_void)12430e13732Spendry static void checkup_mem(P_void)
12530e13732Spendry {
12630e13732Spendry extern struct mallinfo __mallinfo;
12730e13732Spendry if (mem_bytes != __mallinfo.uordbytes) {
12830e13732Spendry if (orig_mem_bytes == 0)
12930e13732Spendry mem_bytes = orig_mem_bytes = __mallinfo.uordbytes;
13030e13732Spendry else {
13130e13732Spendry fprintf(logfp, "%s[%d]: ", progname, mypid);
13230e13732Spendry if (mem_bytes < __mallinfo.uordbytes) {
13330e13732Spendry fprintf(logfp, "ALLOC: %d bytes",
13430e13732Spendry __mallinfo.uordbytes - mem_bytes);
13530e13732Spendry } else {
13630e13732Spendry fprintf(logfp, "FREE: %d bytes",
13730e13732Spendry mem_bytes - __mallinfo.uordbytes);
13830e13732Spendry }
13930e13732Spendry mem_bytes = __mallinfo.uordbytes;
14030e13732Spendry fprintf(logfp, ", making %d missing\n",
14130e13732Spendry mem_bytes - orig_mem_bytes);
14230e13732Spendry }
14330e13732Spendry }
14430e13732Spendry malloc_verify();
14530e13732Spendry }
14630e13732Spendry #endif /* DEBUG_MEM */
14730e13732Spendry
14830e13732Spendry /*
14930e13732Spendry * Take a log format string and expand occurences of %m
15030e13732Spendry * with the current error code take from errno.
15130e13732Spendry */
15230e13732Spendry INLINE
expand_error(f,e)15330e13732Spendry static void expand_error(f, e)
15430e13732Spendry char *f;
15530e13732Spendry char *e;
15630e13732Spendry {
15718436490Spendry #ifndef HAS_STRERROR
15830e13732Spendry extern int sys_nerr;
15930e13732Spendry extern char *sys_errlist[];
16018436490Spendry #endif
16130e13732Spendry char *p;
16230e13732Spendry int error = errno;
16330e13732Spendry
16430e13732Spendry for (p = f; *e = *p; e++, p++) {
16530e13732Spendry if (p[0] == '%' && p[1] == 'm') {
16630e13732Spendry char *errstr;
16718436490Spendry #ifdef HAS_STRERROR
16818436490Spendry errstr = strerror(error);
16918436490Spendry #else
17030e13732Spendry if (error < 0 || error >= sys_nerr)
17130e13732Spendry errstr = 0;
17230e13732Spendry else
17330e13732Spendry errstr = sys_errlist[error];
17418436490Spendry #endif
17530e13732Spendry if (errstr)
17630e13732Spendry strcpy(e, errstr);
17730e13732Spendry else
17830e13732Spendry sprintf(e, "Error %d", error);
17930e13732Spendry e += strlen(e) - 1;
18030e13732Spendry p++;
18130e13732Spendry }
18230e13732Spendry }
18330e13732Spendry }
18430e13732Spendry
18530e13732Spendry /*
18630e13732Spendry * Output the time of day and hostname to the logfile
18730e13732Spendry */
show_time_host_and_name(lvl)18830e13732Spendry static void show_time_host_and_name(lvl)
18930e13732Spendry int lvl;
19030e13732Spendry {
19130e13732Spendry static time_t last_t = 0;
19230e13732Spendry static char *last_ctime = 0;
19330e13732Spendry time_t t = clocktime();
19430e13732Spendry char *sev;
19530e13732Spendry extern char *ctime();
19630e13732Spendry
19730e13732Spendry #if defined(DEBUG) && defined(PARANOID)
19830e13732Spendry extern char **gargv;
19930e13732Spendry #endif /* defined(DEBUG) && defined(PARANOID) */
20030e13732Spendry
20130e13732Spendry if (t != last_t) {
20230e13732Spendry last_ctime = ctime(&t);
20330e13732Spendry last_t = t;
20430e13732Spendry }
20530e13732Spendry
20630e13732Spendry switch (lvl) {
20730e13732Spendry case XLOG_FATAL: sev = "fatal:"; break;
20830e13732Spendry case XLOG_ERROR: sev = "error:"; break;
20930e13732Spendry case XLOG_USER: sev = "user: "; break;
21030e13732Spendry case XLOG_WARNING: sev = "warn: "; break;
21130e13732Spendry case XLOG_INFO: sev = "info: "; break;
21230e13732Spendry case XLOG_DEBUG: sev = "debug:"; break;
21330e13732Spendry case XLOG_MAP: sev = "map: "; break;
21430e13732Spendry case XLOG_STATS: sev = "stats:"; break;
21530e13732Spendry default: sev = "hmm: "; break;
21630e13732Spendry }
21730e13732Spendry fprintf(logfp, "%15.15s %s %s[%d]/%s ",
21830e13732Spendry last_ctime+4, hostname,
21930e13732Spendry #if defined(DEBUG) && defined(PARANOID)
22030e13732Spendry gargv[0],
22130e13732Spendry #else
22230e13732Spendry progname,
22330e13732Spendry #endif /* defined(DEBUG) && defined(PARANOID) */
22430e13732Spendry mypid,
22530e13732Spendry sev);
22630e13732Spendry }
22730e13732Spendry
22830e13732Spendry #ifdef DEBUG
22930e13732Spendry /*VARARGS1*/
dplog(fmt,j,s,_,p,e,n,d,r,y)23030e13732Spendry void dplog(fmt, j,s,_,p,e,n,d,r,y)
23130e13732Spendry char *fmt;
23230e13732Spendry char *j, *s, *_, *p, *e, *n, *d, *r, *y;
23330e13732Spendry {
23430e13732Spendry plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y);
23530e13732Spendry }
23630e13732Spendry
23730e13732Spendry #endif /* DEBUG */
23830e13732Spendry /*VARARGS1*/
plog(lvl,fmt,j,s,_,p,e,n,d,r,y)23930e13732Spendry void plog(lvl, fmt, j,s,_,p,e,n,d,r,y)
24030e13732Spendry int lvl;
24130e13732Spendry char *fmt;
24230e13732Spendry char *j, *s, *_, *p, *e, *n, *d, *r, *y;
24330e13732Spendry {
24430e13732Spendry char msg[1024];
24530e13732Spendry char efmt[1024];
24630e13732Spendry char *ptr = msg;
24730e13732Spendry
24830e13732Spendry if (!(xlog_level & lvl))
24930e13732Spendry return;
25030e13732Spendry
25130e13732Spendry #ifdef DEBUG_MEM
25230e13732Spendry checkup_mem();
25330e13732Spendry #endif /* DEBUG_MEM */
25430e13732Spendry
25530e13732Spendry expand_error(fmt, efmt);
25630e13732Spendry sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y);
25730e13732Spendry ptr += strlen(ptr);
25830e13732Spendry if (ptr[-1] == '\n')
25930e13732Spendry *--ptr = '\0';
26030e13732Spendry #ifdef HAS_SYSLOG
26130e13732Spendry if (syslogging) {
26230e13732Spendry switch(lvl) { /* from mike <mcooper@usc.edu> */
26330e13732Spendry case XLOG_FATAL: lvl = LOG_CRIT; break;
26430e13732Spendry case XLOG_ERROR: lvl = LOG_ERR; break;
26530e13732Spendry case XLOG_USER: lvl = LOG_WARNING; break;
26630e13732Spendry case XLOG_WARNING: lvl = LOG_WARNING; break;
26730e13732Spendry case XLOG_INFO: lvl = LOG_INFO; break;
26830e13732Spendry case XLOG_DEBUG: lvl = LOG_DEBUG; break;
26930e13732Spendry case XLOG_MAP: lvl = LOG_DEBUG; break;
27030e13732Spendry case XLOG_STATS: lvl = LOG_INFO; break;
27130e13732Spendry default: lvl = LOG_ERR; break;
27230e13732Spendry }
27330e13732Spendry syslog(lvl, "%s", msg);
27430e13732Spendry return;
27530e13732Spendry }
27630e13732Spendry #endif /* HAS_SYSLOG */
27730e13732Spendry
27830e13732Spendry *ptr++ = '\n';
27930e13732Spendry *ptr = '\0';
28030e13732Spendry
28130e13732Spendry /*
28230e13732Spendry * Mimic syslog header
28330e13732Spendry */
28430e13732Spendry show_time_host_and_name(lvl);
28530e13732Spendry fwrite(msg, ptr - msg, 1, logfp);
28630e13732Spendry fflush(logfp);
28730e13732Spendry }
28830e13732Spendry
28930e13732Spendry void show_opts P((int ch, struct opt_tab *opts));
show_opts(ch,opts)29030e13732Spendry void show_opts(ch, opts)
29130e13732Spendry int ch;
29230e13732Spendry struct opt_tab *opts;
29330e13732Spendry {
29430e13732Spendry /*
29530e13732Spendry * Display current debug options
29630e13732Spendry */
29730e13732Spendry int i;
29830e13732Spendry int s = '{';
29930e13732Spendry fprintf(stderr, "\t[-%c {no}", ch);
30030e13732Spendry for (i = 0; opts[i].opt; i++) {
30130e13732Spendry fprintf(stderr, "%c%s", s, opts[i].opt);
30230e13732Spendry s = ',';
30330e13732Spendry }
30430e13732Spendry fputs("}]\n", stderr);
30530e13732Spendry }
30630e13732Spendry
30730e13732Spendry int cmdoption P((char *s, struct opt_tab *optb, int *flags));
cmdoption(s,optb,flags)30830e13732Spendry int cmdoption(s, optb, flags)
30930e13732Spendry char *s;
31030e13732Spendry struct opt_tab *optb;
31130e13732Spendry int *flags;
31230e13732Spendry {
31330e13732Spendry char *p = s;
31430e13732Spendry int errs = 0;
31530e13732Spendry
31630e13732Spendry while (p && *p) {
31730e13732Spendry int neg;
31830e13732Spendry char *opt;
31930e13732Spendry struct opt_tab *dp, *dpn = 0;
32030e13732Spendry
32130e13732Spendry s = p;
32230e13732Spendry p = strchr(p, ',');
32330e13732Spendry if (p)
32430e13732Spendry *p = '\0';
32530e13732Spendry
32630e13732Spendry if (s[0] == 'n' && s[1] == 'o') {
32730e13732Spendry opt = s + 2;
32830e13732Spendry neg = 1;
32930e13732Spendry } else {
33030e13732Spendry opt = s;
33130e13732Spendry neg = 0;
33230e13732Spendry }
33330e13732Spendry
33430e13732Spendry /*
33530e13732Spendry * Scan the array of debug options to find the
33630e13732Spendry * corresponding flag value. If it is found
33730e13732Spendry * then set (or clear) the flag (depending on
33830e13732Spendry * whether the option was prefixed with "no").
33930e13732Spendry */
34030e13732Spendry for (dp = optb; dp->opt; dp++) {
34130e13732Spendry if (strcmp(opt, dp->opt) == 0)
34230e13732Spendry break;
34330e13732Spendry if (opt != s && !dpn && strcmp(s, dp->opt) == 0)
34430e13732Spendry dpn = dp;
34530e13732Spendry }
34630e13732Spendry
34730e13732Spendry if (dp->opt || dpn) {
34830e13732Spendry if (!dp->opt) {
34930e13732Spendry dp = dpn;
35030e13732Spendry neg = !neg;
35130e13732Spendry }
35230e13732Spendry if (neg)
35330e13732Spendry *flags &= ~dp->flag;
35430e13732Spendry else
35530e13732Spendry *flags |= dp->flag;
35630e13732Spendry } else {
35730e13732Spendry /*
35830e13732Spendry * This will log to stderr when parsing the command line
35930e13732Spendry * since any -l option will not yet have taken effect.
36030e13732Spendry */
36130e13732Spendry plog(XLOG_USER, "option \"%s\" not recognised", s);
36230e13732Spendry errs++;
36330e13732Spendry }
36430e13732Spendry /*
36530e13732Spendry * Put the comma back
36630e13732Spendry */
36730e13732Spendry if (p)
36830e13732Spendry *p++ = ',';
36930e13732Spendry }
37030e13732Spendry
37130e13732Spendry return errs;
37230e13732Spendry }
37330e13732Spendry
37430e13732Spendry /*
37530e13732Spendry * Switch on/off logging options
37630e13732Spendry */
switch_option(opt)37730e13732Spendry int switch_option(opt)
37830e13732Spendry char *opt;
37930e13732Spendry {
38030e13732Spendry int xl = xlog_level;
38130e13732Spendry int rc = cmdoption(opt, xlog_opt, &xl);
38230e13732Spendry if (rc) {
38330e13732Spendry rc = EINVAL;
38430e13732Spendry } else {
38530e13732Spendry /*
38630e13732Spendry * Keep track of initial log level, and
38730e13732Spendry * don't allow options to be turned off.
38830e13732Spendry */
38930e13732Spendry if (xlog_level_init == ~0)
39030e13732Spendry xlog_level_init = xl;
39130e13732Spendry else
39230e13732Spendry xl |= xlog_level_init;
39330e13732Spendry xlog_level = xl;
39430e13732Spendry }
39530e13732Spendry return rc;
39630e13732Spendry }
39730e13732Spendry
39830e13732Spendry /*
39930e13732Spendry * Change current logfile
40030e13732Spendry */
40130e13732Spendry int switch_to_logfile P((char *logfile));
switch_to_logfile(logfile)40230e13732Spendry int switch_to_logfile(logfile)
40330e13732Spendry char *logfile;
40430e13732Spendry {
40530e13732Spendry FILE *new_logfp = stderr;
40630e13732Spendry
40730e13732Spendry if (logfile) {
40830e13732Spendry #ifdef HAS_SYSLOG
40930e13732Spendry syslogging = 0;
41030e13732Spendry #endif /* HAS_SYSLOG */
41130e13732Spendry if (strcmp(logfile, "/dev/stderr") == 0)
41230e13732Spendry new_logfp = stderr;
41330e13732Spendry else if (strcmp(logfile, "syslog") == 0) {
41430e13732Spendry #ifdef HAS_SYSLOG
41530e13732Spendry syslogging = 1;
41630e13732Spendry new_logfp = stderr;
41730e13732Spendry #if defined(LOG_CONS) && defined(LOG_NOWAIT)
41830e13732Spendry openlog(progname, LOG_PID|LOG_CONS|LOG_NOWAIT,
41930e13732Spendry LOG_DAEMON);
42030e13732Spendry #else
42130e13732Spendry /* 4.2 compat mode - XXX */
42230e13732Spendry openlog(progname, LOG_PID);
42330e13732Spendry #endif /* LOG_CONS && LOG_NOWAIT */
42430e13732Spendry #else
42530e13732Spendry plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
42630e13732Spendry #endif /* HAS_SYSLOG */
42730e13732Spendry } else {
42830e13732Spendry (void) umask(orig_umask);
42930e13732Spendry new_logfp = fopen(logfile, "a");
43030e13732Spendry umask(0);
43130e13732Spendry }
43230e13732Spendry }
43330e13732Spendry
43430e13732Spendry /*
43530e13732Spendry * If we couldn't open a new file, then continue using the old.
43630e13732Spendry */
43730e13732Spendry if (!new_logfp && logfile) {
43830e13732Spendry plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
43930e13732Spendry return 1;
44030e13732Spendry }
44130e13732Spendry /*
44230e13732Spendry * Close the previous file
44330e13732Spendry */
44430e13732Spendry if (logfp && logfp != stderr)
44530e13732Spendry (void) fclose(logfp);
44630e13732Spendry logfp = new_logfp;
44730e13732Spendry return 0;
44830e13732Spendry }
44930e13732Spendry
45030e13732Spendry time_t clock_valid = 0;
45130e13732Spendry time_t xclock_valid = 0;
45230e13732Spendry #ifndef clocktime
clocktime(P_void)45330e13732Spendry time_t clocktime(P_void)
45430e13732Spendry {
45530e13732Spendry time_t now = time(&clock_valid);
45630e13732Spendry if (xclock_valid > now) {
45730e13732Spendry /*
45830e13732Spendry * Someone set the clock back!
45930e13732Spendry */
46030e13732Spendry plog(XLOG_WARNING, "system clock reset");
46130e13732Spendry reschedule_timeouts(now, xclock_valid);
46230e13732Spendry }
46330e13732Spendry return xclock_valid = now;
46430e13732Spendry }
46530e13732Spendry #endif /* clocktime */
466