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