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