xref: /original-bsd/usr.sbin/amd/amd/xutil.c (revision 541b0a81)
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