xref: /original-bsd/usr.sbin/amd/amd/xutil.c (revision f6a299d4)
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.4 (Berkeley) 02/09/92
13  *
14  * $Id: xutil.c,v 5.2.2.1 1992/02/09 15:09:13 jsp beta $
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