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