xref: /original-bsd/sys/kern/subr_prf.c (revision 95ecee29)
1 /*-
2  * Copyright (c) 1986, 1988, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)subr_prf.c	8.2 (Berkeley) 09/23/93
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 & P_CONTROLT && 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 & P_CONTROLT && 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 						continue;
385 			}
386 			if (tmp)
387 				putchar('>', flags, tp);
388 			break;
389 		case 'c':
390 			putchar(va_arg(ap, int), flags, tp);
391 			break;
392 		case 'r':
393 			p = va_arg(ap, char *);
394 			kprintf(p, flags, tp, va_arg(ap, va_list));
395 			break;
396 		case 's':
397 			p = va_arg(ap, char *);
398 			while (ch = *p++)
399 				putchar(ch, flags, tp);
400 			break;
401 		case 'd':
402 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
403 			if ((long)ul < 0) {
404 				putchar('-', flags, tp);
405 				ul = -(long)ul;
406 			}
407 			base = 10;
408 			goto number;
409 		case 'o':
410 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
411 			base = 8;
412 			goto number;
413 		case 'u':
414 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
415 			base = 10;
416 			goto number;
417 		case 'x':
418 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
419 			base = 16;
420 number:			p = ksprintn(ul, base, &tmp);
421 			if (width && (width -= tmp) > 0)
422 				while (width--)
423 					putchar(padc, flags, tp);
424 			while (ch = *p--)
425 				putchar(ch, flags, tp);
426 			break;
427 		default:
428 			putchar('%', flags, tp);
429 			if (lflag)
430 				putchar('l', flags, tp);
431 			/* FALLTHROUGH */
432 		case '%':
433 			putchar(ch, flags, tp);
434 		}
435 	}
436 }
437 
438 /*
439  * Print a character on console or users terminal.  If destination is
440  * the console then the last MSGBUFS characters are saved in msgbuf for
441  * inspection later.
442  */
443 static void
444 putchar(c, flags, tp)
445 	register int c;
446 	int flags;
447 	struct tty *tp;
448 {
449 	extern int msgbufmapped;
450 	register struct msgbuf *mbp;
451 
452 	if (panicstr)
453 		constty = NULL;
454 	if ((flags & TOCONS) && tp == NULL && constty) {
455 		tp = constty;
456 		flags |= TOTTY;
457 	}
458 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
459 	    (flags & TOCONS) && tp == constty)
460 		constty = NULL;
461 	if ((flags & TOLOG) &&
462 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
463 		mbp = msgbufp;
464 		if (mbp->msg_magic != MSG_MAGIC) {
465 			bzero((caddr_t)mbp, sizeof(*mbp));
466 			mbp->msg_magic = MSG_MAGIC;
467 		}
468 		mbp->msg_bufc[mbp->msg_bufx++] = c;
469 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
470 			mbp->msg_bufx = 0;
471 	}
472 	if ((flags & TOCONS) && constty == NULL && c != '\0')
473 		(*v_putc)(c);
474 }
475 
476 /*
477  * Scaled down version of sprintf(3).
478  */
479 #ifdef __STDC__
480 sprintf(char *buf, const char *cfmt, ...)
481 #else
482 sprintf(buf, cfmt, va_alist)
483 	char *buf, *cfmt;
484 #endif
485 {
486 	register const char *fmt = cfmt;
487 	register char *p, *bp;
488 	register int ch, base;
489 	u_long ul;
490 	int lflag;
491 	va_list ap;
492 
493 	va_start(ap, cfmt);
494 	for (bp = buf; ; ) {
495 		while ((ch = *(u_char *)fmt++) != '%')
496 			if ((*bp++ = ch) == '\0')
497 				return ((bp - buf) - 1);
498 
499 		lflag = 0;
500 reswitch:	switch (ch = *(u_char *)fmt++) {
501 		case 'l':
502 			lflag = 1;
503 			goto reswitch;
504 		case 'c':
505 			*bp++ = va_arg(ap, int);
506 			break;
507 		case 's':
508 			p = va_arg(ap, char *);
509 			while (*bp++ = *p++)
510 				continue;
511 			--bp;
512 			break;
513 		case 'd':
514 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
515 			if ((long)ul < 0) {
516 				*bp++ = '-';
517 				ul = -(long)ul;
518 			}
519 			base = 10;
520 			goto number;
521 			break;
522 		case 'o':
523 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
524 			base = 8;
525 			goto number;
526 			break;
527 		case 'u':
528 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
529 			base = 10;
530 			goto number;
531 			break;
532 		case 'x':
533 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
534 			base = 16;
535 number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
536 				*bp++ = ch;
537 			break;
538 		default:
539 			*bp++ = '%';
540 			if (lflag)
541 				*bp++ = 'l';
542 			/* FALLTHROUGH */
543 		case '%':
544 			*bp++ = ch;
545 		}
546 	}
547 	va_end(ap);
548 }
549 
550 /*
551  * Put a number (base <= 16) in a buffer in reverse order; return an
552  * optional length and a pointer to the NULL terminated (preceded?)
553  * buffer.
554  */
555 static char *
556 ksprintn(ul, base, lenp)
557 	register u_long ul;
558 	register int base, *lenp;
559 {					/* A long in base 8, plus NULL. */
560 	static char buf[sizeof(long) * NBBY / 3 + 2];
561 	register char *p;
562 
563 	p = buf;
564 	do {
565 		*++p = "0123456789abcdef"[ul % base];
566 	} while (ul /= base);
567 	if (lenp)
568 		*lenp = p - buf;
569 	return (p);
570 }
571