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