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 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 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) 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; 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 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 */ 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*/ 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*/ 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)); 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)); 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 */ 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)); 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 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