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