1 /*
2 * Copyright (c) 1990 Jan-Simon Pendry
3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry at Imperial College, London.
9 *
10 * %sccs.include.redist.c%
11 *
12 * @(#)xutil.c 8.1 (Berkeley) 06/06/93
13 *
14 * $Id: xutil.c,v 5.2.2.3 1992/03/07 10:36:09 jsp Exp $
15 *
16 */
17
18 #include "config.h"
19 #ifdef HAS_SYSLOG
20 #include <syslog.h>
21 #endif /* HAS_SYSLOG */
22 #ifdef HAS_STRERROR
23 #include <string.h>
24 #endif
25
26 FILE *logfp = stderr; /* Log errors to stderr initially */
27 #ifdef HAS_SYSLOG
28 int syslogging;
29 #endif /* HAS_SYSLOG */
30 int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS;
31 int xlog_level_init = ~0;
32
33 /*
34 * List of log options
35 */
36 struct opt_tab xlog_opt[] = {
37 { "all", XLOG_ALL }, /* All messages */
38 #ifdef DEBUG
39 { "debug", XLOG_DEBUG }, /* Debug messages */
40 #endif /* DEBUG */
41 { "error", XLOG_ERROR }, /* Non-fatal system errors */
42 { "fatal", XLOG_FATAL }, /* Fatal errors */
43 { "info", XLOG_INFO }, /* Information */
44 { "map", XLOG_MAP }, /* Map errors */
45 { "stats", XLOG_STATS }, /* Additional statistical information */
46 { "user", XLOG_USER }, /* Non-fatal user errors */
47 { "warn", XLOG_WARNING }, /* Warnings */
48 { "warning", XLOG_WARNING }, /* Warnings */
49 { 0, 0 }
50 };
51
xmalloc(len)52 voidp xmalloc(len)
53 int len;
54 {
55 voidp p;
56 int retries = 600;
57
58 /*
59 * Avoid malloc's which return NULL for malloc(0)
60 */
61 if (len == 0)
62 len = 1;
63
64 do {
65 p = (voidp) malloc((unsigned) len);
66 if (p) {
67 #if defined(DEBUG) && defined(DEBUG_MEM)
68 Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
69 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
70 return p;
71 }
72 if (retries > 0) {
73 plog(XLOG_ERROR, "Retrying memory allocation");
74 sleep(1);
75 }
76 } while (--retries);
77
78 plog(XLOG_FATAL, "Out of memory");
79 going_down(1);
80
81 abort();
82
83 return 0;
84 }
85
xrealloc(ptr,len)86 voidp xrealloc(ptr, len)
87 voidp ptr;
88 int len;
89 {
90 #if defined(DEBUG) && defined(DEBUG_MEM)
91 Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
92 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
93
94 if (len == 0)
95 len = 1;
96
97 if (ptr)
98 ptr = (voidp) realloc(ptr, (unsigned) len);
99 else
100 ptr = (voidp) xmalloc((unsigned) len);
101
102 if (!ptr) {
103 plog(XLOG_FATAL, "Out of memory in realloc");
104 going_down(1);
105 abort();
106 }
107 return ptr;
108 }
109
110 #if defined(DEBUG) && defined(DEBUG_MEM)
xfree(f,l,p)111 xfree(f, l, p)
112 char *f;
113 int l;
114 voidp p;
115 {
116 Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p);
117 #undef free
118 free(p);
119 }
120 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
121 #ifdef DEBUG_MEM
122 static int mem_bytes;
123 static int orig_mem_bytes;
checkup_mem(P_void)124 static void checkup_mem(P_void)
125 {
126 extern struct mallinfo __mallinfo;
127 if (mem_bytes != __mallinfo.uordbytes) {
128 if (orig_mem_bytes == 0)
129 mem_bytes = orig_mem_bytes = __mallinfo.uordbytes;
130 else {
131 fprintf(logfp, "%s[%d]: ", progname, mypid);
132 if (mem_bytes < __mallinfo.uordbytes) {
133 fprintf(logfp, "ALLOC: %d bytes",
134 __mallinfo.uordbytes - mem_bytes);
135 } else {
136 fprintf(logfp, "FREE: %d bytes",
137 mem_bytes - __mallinfo.uordbytes);
138 }
139 mem_bytes = __mallinfo.uordbytes;
140 fprintf(logfp, ", making %d missing\n",
141 mem_bytes - orig_mem_bytes);
142 }
143 }
144 malloc_verify();
145 }
146 #endif /* DEBUG_MEM */
147
148 /*
149 * Take a log format string and expand occurences of %m
150 * with the current error code take from errno.
151 */
152 INLINE
expand_error(f,e)153 static void expand_error(f, e)
154 char *f;
155 char *e;
156 {
157 #ifndef HAS_STRERROR
158 extern int sys_nerr;
159 extern char *sys_errlist[];
160 #endif
161 char *p;
162 int error = errno;
163
164 for (p = f; *e = *p; e++, p++) {
165 if (p[0] == '%' && p[1] == 'm') {
166 char *errstr;
167 #ifdef HAS_STRERROR
168 errstr = strerror(error);
169 #else
170 if (error < 0 || error >= sys_nerr)
171 errstr = 0;
172 else
173 errstr = sys_errlist[error];
174 #endif
175 if (errstr)
176 strcpy(e, errstr);
177 else
178 sprintf(e, "Error %d", error);
179 e += strlen(e) - 1;
180 p++;
181 }
182 }
183 }
184
185 /*
186 * Output the time of day and hostname to the logfile
187 */
show_time_host_and_name(lvl)188 static void show_time_host_and_name(lvl)
189 int lvl;
190 {
191 static time_t last_t = 0;
192 static char *last_ctime = 0;
193 time_t t = clocktime();
194 char *sev;
195 extern char *ctime();
196
197 #if defined(DEBUG) && defined(PARANOID)
198 extern char **gargv;
199 #endif /* defined(DEBUG) && defined(PARANOID) */
200
201 if (t != last_t) {
202 last_ctime = ctime(&t);
203 last_t = t;
204 }
205
206 switch (lvl) {
207 case XLOG_FATAL: sev = "fatal:"; break;
208 case XLOG_ERROR: sev = "error:"; break;
209 case XLOG_USER: sev = "user: "; break;
210 case XLOG_WARNING: sev = "warn: "; break;
211 case XLOG_INFO: sev = "info: "; break;
212 case XLOG_DEBUG: sev = "debug:"; break;
213 case XLOG_MAP: sev = "map: "; break;
214 case XLOG_STATS: sev = "stats:"; break;
215 default: sev = "hmm: "; break;
216 }
217 fprintf(logfp, "%15.15s %s %s[%d]/%s ",
218 last_ctime+4, hostname,
219 #if defined(DEBUG) && defined(PARANOID)
220 gargv[0],
221 #else
222 progname,
223 #endif /* defined(DEBUG) && defined(PARANOID) */
224 mypid,
225 sev);
226 }
227
228 #ifdef DEBUG
229 /*VARARGS1*/
dplog(fmt,j,s,_,p,e,n,d,r,y)230 void dplog(fmt, j,s,_,p,e,n,d,r,y)
231 char *fmt;
232 char *j, *s, *_, *p, *e, *n, *d, *r, *y;
233 {
234 plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y);
235 }
236
237 #endif /* DEBUG */
238 /*VARARGS1*/
plog(lvl,fmt,j,s,_,p,e,n,d,r,y)239 void plog(lvl, fmt, j,s,_,p,e,n,d,r,y)
240 int lvl;
241 char *fmt;
242 char *j, *s, *_, *p, *e, *n, *d, *r, *y;
243 {
244 char msg[1024];
245 char efmt[1024];
246 char *ptr = msg;
247
248 if (!(xlog_level & lvl))
249 return;
250
251 #ifdef DEBUG_MEM
252 checkup_mem();
253 #endif /* DEBUG_MEM */
254
255 expand_error(fmt, efmt);
256 sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y);
257 ptr += strlen(ptr);
258 if (ptr[-1] == '\n')
259 *--ptr = '\0';
260 #ifdef HAS_SYSLOG
261 if (syslogging) {
262 switch(lvl) { /* from mike <mcooper@usc.edu> */
263 case XLOG_FATAL: lvl = LOG_CRIT; break;
264 case XLOG_ERROR: lvl = LOG_ERR; break;
265 case XLOG_USER: lvl = LOG_WARNING; break;
266 case XLOG_WARNING: lvl = LOG_WARNING; break;
267 case XLOG_INFO: lvl = LOG_INFO; break;
268 case XLOG_DEBUG: lvl = LOG_DEBUG; break;
269 case XLOG_MAP: lvl = LOG_DEBUG; break;
270 case XLOG_STATS: lvl = LOG_INFO; break;
271 default: lvl = LOG_ERR; break;
272 }
273 syslog(lvl, "%s", msg);
274 return;
275 }
276 #endif /* HAS_SYSLOG */
277
278 *ptr++ = '\n';
279 *ptr = '\0';
280
281 /*
282 * Mimic syslog header
283 */
284 show_time_host_and_name(lvl);
285 fwrite(msg, ptr - msg, 1, logfp);
286 fflush(logfp);
287 }
288
289 void show_opts P((int ch, struct opt_tab *opts));
show_opts(ch,opts)290 void show_opts(ch, opts)
291 int ch;
292 struct opt_tab *opts;
293 {
294 /*
295 * Display current debug options
296 */
297 int i;
298 int s = '{';
299 fprintf(stderr, "\t[-%c {no}", ch);
300 for (i = 0; opts[i].opt; i++) {
301 fprintf(stderr, "%c%s", s, opts[i].opt);
302 s = ',';
303 }
304 fputs("}]\n", stderr);
305 }
306
307 int cmdoption P((char *s, struct opt_tab *optb, int *flags));
cmdoption(s,optb,flags)308 int cmdoption(s, optb, flags)
309 char *s;
310 struct opt_tab *optb;
311 int *flags;
312 {
313 char *p = s;
314 int errs = 0;
315
316 while (p && *p) {
317 int neg;
318 char *opt;
319 struct opt_tab *dp, *dpn = 0;
320
321 s = p;
322 p = strchr(p, ',');
323 if (p)
324 *p = '\0';
325
326 if (s[0] == 'n' && s[1] == 'o') {
327 opt = s + 2;
328 neg = 1;
329 } else {
330 opt = s;
331 neg = 0;
332 }
333
334 /*
335 * Scan the array of debug options to find the
336 * corresponding flag value. If it is found
337 * then set (or clear) the flag (depending on
338 * whether the option was prefixed with "no").
339 */
340 for (dp = optb; dp->opt; dp++) {
341 if (strcmp(opt, dp->opt) == 0)
342 break;
343 if (opt != s && !dpn && strcmp(s, dp->opt) == 0)
344 dpn = dp;
345 }
346
347 if (dp->opt || dpn) {
348 if (!dp->opt) {
349 dp = dpn;
350 neg = !neg;
351 }
352 if (neg)
353 *flags &= ~dp->flag;
354 else
355 *flags |= dp->flag;
356 } else {
357 /*
358 * This will log to stderr when parsing the command line
359 * since any -l option will not yet have taken effect.
360 */
361 plog(XLOG_USER, "option \"%s\" not recognised", s);
362 errs++;
363 }
364 /*
365 * Put the comma back
366 */
367 if (p)
368 *p++ = ',';
369 }
370
371 return errs;
372 }
373
374 /*
375 * Switch on/off logging options
376 */
switch_option(opt)377 int switch_option(opt)
378 char *opt;
379 {
380 int xl = xlog_level;
381 int rc = cmdoption(opt, xlog_opt, &xl);
382 if (rc) {
383 rc = EINVAL;
384 } else {
385 /*
386 * Keep track of initial log level, and
387 * don't allow options to be turned off.
388 */
389 if (xlog_level_init == ~0)
390 xlog_level_init = xl;
391 else
392 xl |= xlog_level_init;
393 xlog_level = xl;
394 }
395 return rc;
396 }
397
398 /*
399 * Change current logfile
400 */
401 int switch_to_logfile P((char *logfile));
switch_to_logfile(logfile)402 int switch_to_logfile(logfile)
403 char *logfile;
404 {
405 FILE *new_logfp = stderr;
406
407 if (logfile) {
408 #ifdef HAS_SYSLOG
409 syslogging = 0;
410 #endif /* HAS_SYSLOG */
411 if (strcmp(logfile, "/dev/stderr") == 0)
412 new_logfp = stderr;
413 else if (strcmp(logfile, "syslog") == 0) {
414 #ifdef HAS_SYSLOG
415 syslogging = 1;
416 new_logfp = stderr;
417 #if defined(LOG_CONS) && defined(LOG_NOWAIT)
418 openlog(progname, LOG_PID|LOG_CONS|LOG_NOWAIT,
419 LOG_DAEMON);
420 #else
421 /* 4.2 compat mode - XXX */
422 openlog(progname, LOG_PID);
423 #endif /* LOG_CONS && LOG_NOWAIT */
424 #else
425 plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
426 #endif /* HAS_SYSLOG */
427 } else {
428 (void) umask(orig_umask);
429 new_logfp = fopen(logfile, "a");
430 umask(0);
431 }
432 }
433
434 /*
435 * If we couldn't open a new file, then continue using the old.
436 */
437 if (!new_logfp && logfile) {
438 plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
439 return 1;
440 }
441 /*
442 * Close the previous file
443 */
444 if (logfp && logfp != stderr)
445 (void) fclose(logfp);
446 logfp = new_logfp;
447 return 0;
448 }
449
450 time_t clock_valid = 0;
451 time_t xclock_valid = 0;
452 #ifndef clocktime
clocktime(P_void)453 time_t clocktime(P_void)
454 {
455 time_t now = time(&clock_valid);
456 if (xclock_valid > now) {
457 /*
458 * Someone set the clock back!
459 */
460 plog(XLOG_WARNING, "system clock reset");
461 reschedule_timeouts(now, xclock_valid);
462 }
463 return xclock_valid = now;
464 }
465 #endif /* clocktime */
466