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