xref: /csrg-svn/sys/kern/subr_prf.c (revision 52877)
1 /*-
2  * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)subr_prf.c	7.37 (Berkeley) 03/08/92
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/buf.h>
13 #include <sys/conf.h>
14 #include <sys/reboot.h>
15 #include <sys/msgbuf.h>
16 #include <sys/proc.h>
17 #include <sys/ioctl.h>
18 #include <sys/vnode.h>
19 #include <sys/file.h>
20 #include <sys/tty.h>
21 #include <sys/tprintf.h>
22 #include <sys/syslog.h>
23 #include <sys/malloc.h>
24 
25 /*
26  * Note that stdarg.h and the ANSI style va_start macro is used for both
27  * ANSI and traditional C compilers.
28  */
29 #include <machine/stdarg.h>
30 
31 #ifdef KADB
32 #include "machine/kdbparam.h"
33 #endif
34 
35 #define TOCONS	0x01
36 #define TOTTY	0x02
37 #define TOLOG	0x04
38 
39 struct	tty *constty;			/* pointer to console "window" tty */
40 
41 extern	cnputc();			/* standard console putc */
42 int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
43 
44 void  logpri __P((int level));
45 static void  putchar __P((int ch, int flags, struct tty *tp));
46 static char *ksprintn __P((u_long num, int base, int *len));
47 void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
48 
49 int consintr = 1;			/* Ok to handle console interrupts? */
50 
51 /*
52  * Variable panicstr contains argument to first call to panic; used as flag
53  * to indicate that the kernel has already called panic.
54  */
55 const char *panicstr;
56 
57 /*
58  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
59  * and then reboots.  If we are called twice, then we avoid trying to sync
60  * the disks as this often leads to recursive panics.
61  */
62 #ifdef __GNUC__
63 volatile void boot(int flags);	/* boot() does not return */
64 volatile			/* panic() does not return */
65 #endif
66 void
67 #ifdef __STDC__
68 panic(const char *fmt, ...)
69 #else
70 panic(fmt, va_alist)
71 	char *fmt;
72 #endif
73 {
74 	int bootopt;
75 	va_list ap;
76 
77 	bootopt = RB_AUTOBOOT | RB_DUMP;
78 	if (panicstr)
79 		bootopt |= RB_NOSYNC;
80 	else
81 		panicstr = fmt;
82 
83 	va_start(ap, fmt);
84 	printf("panic: %r\n", fmt, ap);
85 	va_end(ap);
86 
87 #ifdef KGDB
88 	kgdb_panic();
89 #endif
90 #ifdef KADB
91 	if (boothowto & RB_KDB)
92 		kdbpanic();
93 #endif
94 	boot(bootopt);
95 }
96 
97 /*
98  * Warn that a system table is full.
99  */
100 void
101 tablefull(tab)
102 	const char *tab;
103 {
104 
105 	log(LOG_ERR, "%s: table is full\n", tab);
106 }
107 
108 /*
109  * Uprintf prints to the controlling terminal for the current process.
110  * It may block if the tty queue is overfull.  No message is printed if
111  * the queue does not clear in a reasonable time.
112  */
113 void
114 #ifdef __STDC__
115 uprintf(const char *fmt, ...)
116 #else
117 uprintf(fmt, va_alist)
118 	char *fmt;
119 #endif
120 {
121 	register struct proc *p = curproc;
122 	va_list ap;
123 
124 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
125 		va_start(ap, fmt);
126 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
127 		va_end(ap);
128 	}
129 }
130 
131 tpr_t
132 tprintf_open(p)
133 	register struct proc *p;
134 {
135 
136 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
137 		SESSHOLD(p->p_session);
138 		return ((tpr_t) p->p_session);
139 	}
140 	return ((tpr_t) NULL);
141 }
142 
143 void
144 tprintf_close(sess)
145 	tpr_t sess;
146 {
147 
148 	if (sess)
149 		SESSRELE((struct session *) sess);
150 }
151 
152 /*
153  * tprintf prints on the controlling terminal associated
154  * with the given session.
155  */
156 void
157 #ifdef __STDC__
158 tprintf(tpr_t tpr, const char *fmt, ...)
159 #else
160 tprintf(tpr, fmt, va_alist)
161 	tpr_t tpr;
162 	char *fmt;
163 #endif
164 {
165 	register struct session *sess = (struct session *)tpr;
166 	struct tty *tp = NULL;
167 	int flags = TOLOG;
168 	va_list ap;
169 
170 	logpri(LOG_INFO);
171 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
172 		flags |= TOTTY;
173 		tp = sess->s_ttyp;
174 	}
175 	va_start(ap, fmt);
176 	kprintf(fmt, flags, tp, ap);
177 	va_end(ap);
178 	logwakeup();
179 }
180 
181 /*
182  * Ttyprintf displays a message on a tty; it should be used only by
183  * the tty driver, or anything that knows the underlying tty will not
184  * be revoke(2)'d away.  Other callers should use tprintf.
185  */
186 void
187 #ifdef __STDC__
188 ttyprintf(struct tty *tp, const char *fmt, ...)
189 #else
190 ttyprintf(tp, fmt, va_alist)
191 	struct tty *tp;
192 	char *fmt;
193 #endif
194 {
195 	va_list ap;
196 
197 	va_start(ap, fmt);
198 	kprintf(fmt, TOTTY, tp, ap);
199 	va_end(ap);
200 }
201 
202 extern	int log_open;
203 
204 /*
205  * Log writes to the log buffer, and guarantees not to sleep (so can be
206  * called by interrupt routines).  If there is no process reading the
207  * log yet, it writes to the console also.
208  */
209 void
210 #ifdef __STDC__
211 log(int level, const char *fmt, ...)
212 #else
213 log(level, fmt, va_alist)
214 	int level;
215 	char *fmt;
216 #endif
217 {
218 	register int s;
219 	va_list ap;
220 
221 	s = splhigh();
222 	logpri(level);
223 	va_start(ap, fmt);
224 	kprintf(fmt, TOLOG, NULL, ap);
225 	splx(s);
226 	va_end(ap);
227 	if (!log_open) {
228 		va_start(ap, fmt);
229 		kprintf(fmt, TOCONS, NULL, ap);
230 		va_end(ap);
231 	}
232 	logwakeup();
233 }
234 
235 void
236 logpri(level)
237 	int level;
238 {
239 	register int ch;
240 	register char *p;
241 
242 	putchar('<', TOLOG, NULL);
243 	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
244 		putchar(ch, TOLOG, NULL);
245 	putchar('>', TOLOG, NULL);
246 }
247 
248 void
249 #ifdef __STDC__
250 addlog(const char *fmt, ...)
251 #else
252 addlog(fmt, va_alist)
253 	char *fmt;
254 #endif
255 {
256 	register int s;
257 	va_list ap;
258 
259 	s = splhigh();
260 	va_start(ap, fmt);
261 	kprintf(fmt, TOLOG, NULL, ap);
262 	splx(s);
263 	va_end(ap);
264 	if (!log_open) {
265 		va_start(ap, fmt);
266 		kprintf(fmt, TOCONS, NULL, ap);
267 		va_end(ap);
268 	}
269 	logwakeup();
270 }
271 
272 void
273 #ifdef __STDC__
274 printf(const char *fmt, ...)
275 #else
276 printf(fmt, va_alist)
277 	char *fmt;
278 #endif
279 {
280 	va_list ap;
281 	register int savintr;
282 
283 	savintr = consintr;		/* disable interrupts */
284 	consintr = 0;
285 	va_start(ap, fmt);
286 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
287 	va_end(ap);
288 	if (!panicstr)
289 		logwakeup();
290 	consintr = savintr;		/* reenable interrupts */
291 }
292 
293 /*
294  * Scaled down version of printf(3).
295  *
296  * Two additional formats:
297  *
298  * The format %b is supported to decode error registers.
299  * Its usage is:
300  *
301  *	printf("reg=%b\n", regval, "<base><arg>*");
302  *
303  * where <base> is the output base expressed as a control character, e.g.
304  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
305  * the first of which gives the bit number to be inspected (origin 1), and
306  * the next characters (up to a control character, i.e. a character <= 32),
307  * give the name of the register.  Thus:
308  *
309  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
310  *
311  * would produce output:
312  *
313  *	reg=3<BITTWO,BITONE>
314  *
315  * The format %r passes an additional format string and argument list
316  * recursively.  Its usage is:
317  *
318  * fn(char *fmt, ...)
319  * {
320  *	va_list ap;
321  *	va_start(ap, fmt);
322  *	printf("prefix: %r: suffix\n", fmt, ap);
323  *	va_end(ap);
324  * }
325  *
326  * Space or zero padding and a field width are supported for the numeric
327  * formats only.
328  */
329 void
330 kprintf(fmt, flags, tp, ap)
331 	register const char *fmt;
332 	int flags;
333 	struct tty *tp;
334 	va_list ap;
335 {
336 	register char *p, *q;
337 	register int ch, n;
338 	u_long ul;
339 	int base, lflag, tmp, width;
340 	char padc;
341 
342 	for (;;) {
343 		padc = ' ';
344 		width = 0;
345 		while ((ch = *(u_char *)fmt++) != '%') {
346 			if (ch == '\0')
347 				return;
348 			putchar(ch, flags, tp);
349 		}
350 		lflag = 0;
351 reswitch:	switch (ch = *(u_char *)fmt++) {
352 		case '0':
353 			padc = '0';
354 			goto reswitch;
355 		case '1': case '2': case '3': case '4':
356 		case '5': case '6': case '7': case '8': case '9':
357 			for (width = 0;; ++fmt) {
358 				width = width * 10 + ch - '0';
359 				ch = *fmt;
360 				if (ch < '0' || ch > '9')
361 					break;
362 			}
363 			goto reswitch;
364 		case 'l':
365 			lflag = 1;
366 			goto reswitch;
367 		case 'b':
368 			ul = va_arg(ap, int);
369 			p = va_arg(ap, char *);
370 			for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
371 				putchar(ch, flags, tp);
372 
373 			if (!ul)
374 				break;
375 
376 			for (tmp = 0; n = *p++;) {
377 				if (ul & (1 << (n - 1))) {
378 					putchar(tmp ? ',' : '<', flags, tp);
379 					for (; (n = *p) > ' '; ++p)
380 						putchar(n, flags, tp);
381 					tmp = 1;
382 				} else
383 					for (; *p > ' '; ++p);
384 			}
385 			if (tmp)
386 				putchar('>', flags, tp);
387 			break;
388 		case 'c':
389 			putchar(va_arg(ap, int), flags, tp);
390 			break;
391 		case 'r':
392 			p = va_arg(ap, char *);
393 			kprintf(p, flags, tp, va_arg(ap, va_list));
394 			break;
395 		case 's':
396 			p = va_arg(ap, char *);
397 			while (ch = *p++)
398 				putchar(ch, flags, tp);
399 			break;
400 		case 'd':
401 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
402 			if ((long)ul < 0) {
403 				putchar('-', flags, tp);
404 				ul = -(long)ul;
405 			}
406 			base = 10;
407 			goto number;
408 		case 'o':
409 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
410 			base = 8;
411 			goto number;
412 		case 'u':
413 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
414 			base = 10;
415 			goto number;
416 		case 'x':
417 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
418 			base = 16;
419 number:			p = ksprintn(ul, base, &tmp);
420 			if (width && (width -= tmp) > 0)
421 				while (width--)
422 					putchar(padc, flags, tp);
423 			while (ch = *p--)
424 				putchar(ch, flags, tp);
425 			break;
426 		default:
427 			putchar('%', flags, tp);
428 			if (lflag)
429 				putchar('l', flags, tp);
430 			/* FALLTHROUGH */
431 		case '%':
432 			putchar(ch, flags, tp);
433 		}
434 	}
435 }
436 
437 /*
438  * Print a character on console or users terminal.  If destination is
439  * the console then the last MSGBUFS characters are saved in msgbuf for
440  * inspection later.
441  */
442 static void
443 putchar(c, flags, tp)
444 	register int c;
445 	int flags;
446 	struct tty *tp;
447 {
448 	extern int msgbufmapped;
449 	register struct msgbuf *mbp;
450 
451 	if (panicstr)
452 		constty = NULL;
453 	if ((flags & TOCONS) && tp == NULL && constty) {
454 		tp = constty;
455 		flags |= TOTTY;
456 	}
457 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
458 	    (flags & TOCONS) && tp == constty)
459 		constty = NULL;
460 	if ((flags & TOLOG) &&
461 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
462 		mbp = msgbufp;
463 		if (mbp->msg_magic != MSG_MAGIC) {
464 			bzero((caddr_t)mbp, sizeof(*mbp));
465 			mbp->msg_magic = MSG_MAGIC;
466 		}
467 		mbp->msg_bufc[mbp->msg_bufx++] = c;
468 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
469 			mbp->msg_bufx = 0;
470 	}
471 	if ((flags & TOCONS) && constty == NULL && c != '\0')
472 		(*v_putc)(c);
473 }
474 
475 /*
476  * Scaled down version of sprintf(3).
477  */
478 #ifdef __STDC__
479 sprintf(char *buf, const char *cfmt, ...)
480 #else
481 sprintf(buf, cfmt, va_alist)
482 	char *buf, *cfmt;
483 #endif
484 {
485 	register const char *fmt = cfmt;
486 	register char *p, *bp;
487 	register int ch, base;
488 	u_long ul;
489 	int lflag;
490 	va_list ap;
491 
492 	va_start(ap, cfmt);
493 	for (bp = buf; ; ) {
494 		while ((ch = *(u_char *)fmt++) != '%')
495 			if ((*bp++ = ch) == '\0')
496 				return ((bp - buf) - 1);
497 
498 		lflag = 0;
499 reswitch:	switch (ch = *(u_char *)fmt++) {
500 		case 'l':
501 			lflag = 1;
502 			goto reswitch;
503 		case 'c':
504 			*bp++ = va_arg(ap, int);
505 			break;
506 		case 's':
507 			p = va_arg(ap, char *);
508 			while (*bp++ = *p++)
509 				continue;
510 			--bp;
511 			break;
512 		case 'd':
513 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
514 			if ((long)ul < 0) {
515 				*bp++ = '-';
516 				ul = -(long)ul;
517 			}
518 			base = 10;
519 			goto number;
520 			break;
521 		case 'o':
522 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
523 			base = 8;
524 			goto number;
525 			break;
526 		case 'u':
527 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
528 			base = 10;
529 			goto number;
530 			break;
531 		case 'x':
532 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
533 			base = 16;
534 number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
535 				*bp++ = ch;
536 			break;
537 		default:
538 			*bp++ = '%';
539 			if (lflag)
540 				*bp++ = 'l';
541 			/* FALLTHROUGH */
542 		case '%':
543 			*bp++ = ch;
544 		}
545 	}
546 	va_end(ap);
547 }
548 
549 /*
550  * Put a number (base <= 16) in a buffer in reverse order; return an
551  * optional length and a pointer to the NULL terminated (preceded?)
552  * buffer.
553  */
554 static char *
555 ksprintn(ul, base, lenp)
556 	register u_long ul;
557 	register int base, *lenp;
558 {					/* A long in base 8, plus NULL. */
559 	static char buf[sizeof(long) * NBBY / 3 + 2];
560 	register char *p;
561 
562 	p = buf;
563 	do {
564 		*++p = "0123456789abcdef"[ul % base];
565 	} while (ul /= base);
566 	if (lenp)
567 		*lenp = p - buf;
568 	return (p);
569 }
570