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