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