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