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