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