xref: /freebsd/sys/kern/subr_prf.c (revision ef5d438ed4bc17ad7ece3e40fe4d1f9baf3aadf7)
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.28 1996/01/25 00:17:22 bde Exp $
40  */
41 
42 #include "opt_ddb.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/reboot.h>
47 #include <sys/msgbuf.h>
48 #include <sys/proc.h>
49 #include <sys/vnode.h>
50 #include <sys/tty.h>
51 #include <sys/tprintf.h>
52 #include <sys/syslog.h>
53 #include <sys/malloc.h>
54 #include <machine/cons.h>
55 
56 /*
57  * Note that stdarg.h and the ANSI style va_start macro is used for both
58  * ANSI and traditional C compilers.
59  */
60 #include <machine/stdarg.h>
61 
62 #ifdef KADB
63 #include <machine/kdbparam.h>
64 #endif
65 
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 static void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
74 
75 static void  logpri __P((int level));
76 static void  msglogchar(int c, void *dummyarg);
77 struct putchar_arg {int flags; struct tty *tty; };
78 static void  putchar __P((int ch, void *arg));
79 static char *ksprintn __P((u_long num, int base, int *len));
80 
81 static 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 panic(const char *fmt, ...)
99 {
100 	int bootopt;
101 	va_list ap;
102 
103 	bootopt = RB_AUTOBOOT | RB_DUMP;
104 	if (panicstr)
105 		bootopt |= RB_NOSYNC;
106 	else
107 		panicstr = fmt;
108 
109 	printf("panic: ");
110 	va_start(ap, fmt);
111 	vprintf(fmt, ap);
112 	va_end(ap);
113 	printf("\n");
114 
115 #ifdef KGDB
116 	kgdb_panic();
117 #endif
118 #ifdef KADB
119 	if (boothowto & RB_KDB)
120 		kdbpanic();
121 #endif
122 #ifdef DDB
123 	Debugger ("panic");
124 #endif
125 	boot(bootopt);
126 }
127 
128 /*
129  * Warn that a system table is full.
130  */
131 void
132 tablefull(tab)
133 	const char *tab;
134 {
135 
136 	log(LOG_ERR, "%s: table is full\n", tab);
137 }
138 
139 /*
140  * Uprintf prints to the controlling terminal for the current process.
141  * It may block if the tty queue is overfull.  No message is printed if
142  * the queue does not clear in a reasonable time.
143  */
144 void
145 uprintf(const char *fmt, ...)
146 {
147 	struct proc *p = curproc;
148 	va_list ap;
149 	struct putchar_arg pca;
150 
151 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
152 		va_start(ap, fmt);
153 		pca.tty = p->p_session->s_ttyp;
154 		pca.flags = TOTTY;
155 		kvprintf(fmt, putchar, &pca, 10, ap);
156 		va_end(ap);
157 	}
158 }
159 
160 tpr_t
161 tprintf_open(p)
162 	register struct proc *p;
163 {
164 
165 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
166 		SESSHOLD(p->p_session);
167 		return ((tpr_t) p->p_session);
168 	}
169 	return ((tpr_t) NULL);
170 }
171 
172 void
173 tprintf_close(sess)
174 	tpr_t sess;
175 {
176 
177 	if (sess)
178 		SESSRELE((struct session *) sess);
179 }
180 
181 /*
182  * tprintf prints on the controlling terminal associated
183  * with the given session.
184  */
185 void
186 tprintf(tpr_t tpr, const char *fmt, ...)
187 {
188 	register struct session *sess = (struct session *)tpr;
189 	struct tty *tp = NULL;
190 	int flags = TOLOG;
191 	va_list ap;
192 	struct putchar_arg pca;
193 
194 	logpri(LOG_INFO);
195 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
196 		flags |= TOTTY;
197 		tp = sess->s_ttyp;
198 	}
199 	va_start(ap, fmt);
200 	pca.tty = tp;
201 	pca.flags = flags;
202 	kvprintf(fmt, putchar, &pca, 10, ap);
203 	va_end(ap);
204 	logwakeup();
205 }
206 
207 /*
208  * Ttyprintf displays a message on a tty; it should be used only by
209  * the tty driver, or anything that knows the underlying tty will not
210  * be revoke(2)'d away.  Other callers should use tprintf.
211  */
212 void
213 ttyprintf(struct tty *tp, const char *fmt, ...)
214 {
215 	va_list ap;
216 	struct putchar_arg pca;
217 	va_start(ap, fmt);
218 	pca.tty = tp;
219 	pca.flags = TOTTY;
220 	kvprintf(fmt, putchar, &pca, 10, ap);
221 	va_end(ap);
222 }
223 
224 extern	int log_open;
225 
226 /*
227  * Log writes to the log buffer, and guarantees not to sleep (so can be
228  * called by interrupt routines).  If there is no process reading the
229  * log yet, it writes to the console also.
230  */
231 void
232 log(int level, const char *fmt, ...)
233 {
234 	register int s;
235 	va_list ap;
236 
237 	s = splhigh();
238 	logpri(level);
239 	va_start(ap, fmt);
240 
241 	kvprintf(fmt, msglogchar, NULL, 10, ap);
242 	va_end(ap);
243 
244 	splx(s);
245 	if (!log_open) {
246 		struct putchar_arg pca;
247 		va_start(ap, fmt);
248 		pca.tty = NULL;
249 		pca.flags = TOCONS;
250 		kvprintf(fmt, putchar, &pca, 10, ap);
251 		va_end(ap);
252 	}
253 	logwakeup();
254 }
255 
256 static void
257 logpri(level)
258 	int level;
259 {
260 	register char *p;
261 
262 	msglogchar('<', NULL);
263 	for (p = ksprintn((u_long)level, 10, NULL); *p;)
264 		msglogchar(*p--, NULL);
265 	msglogchar('>', NULL);
266 }
267 
268 void
269 addlog(const char *fmt, ...)
270 {
271 	register int s;
272 	va_list ap;
273 
274 	s = splhigh();
275 	va_start(ap, fmt);
276 	kvprintf(fmt, msglogchar, NULL, 10, ap);
277 	splx(s);
278 	va_end(ap);
279 	if (!log_open) {
280 		struct putchar_arg pca;
281 		va_start(ap, fmt);
282 		pca.tty = NULL;
283 		pca.flags = TOCONS;
284 		kvprintf(fmt, putchar, &pca, 10, ap);
285 		va_end(ap);
286 	}
287 	logwakeup();
288 }
289 
290 int
291 printf(const char *fmt, ...)
292 {
293 	va_list ap;
294 	register int savintr;
295 	struct putchar_arg pca;
296 	int retval;
297 
298 	savintr = consintr;		/* disable interrupts */
299 	consintr = 0;
300 	va_start(ap, fmt);
301 	pca.tty = NULL;
302 	pca.flags = TOCONS | TOLOG;
303 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
304 	va_end(ap);
305 	if (!panicstr)
306 		logwakeup();
307 	consintr = savintr;		/* reenable interrupts */
308 	return retval;
309 }
310 
311 void
312 vprintf(const char *fmt, va_list ap)
313 {
314 	register int savintr;
315 	struct putchar_arg pca;
316 
317 	savintr = consintr;		/* disable interrupts */
318 	consintr = 0;
319 	pca.tty = NULL;
320 	pca.flags = TOCONS | TOLOG;
321 	kvprintf(fmt, putchar, &pca, 10, ap);
322 	if (!panicstr)
323 		logwakeup();
324 	consintr = savintr;		/* reenable interrupts */
325 }
326 
327 /*
328  * Print a character on console or users terminal.  If destination is
329  * the console then the last MSGBUFS characters are saved in msgbuf for
330  * inspection later.
331  */
332 static void
333 putchar(int c, void *arg)
334 {
335 	struct putchar_arg *ap = (struct putchar_arg*) arg;
336 	int flags = ap->flags;
337 	struct tty *tp = ap->tty;
338 	if (panicstr)
339 		constty = NULL;
340 	if ((flags & TOCONS) && tp == NULL && constty) {
341 		tp = constty;
342 		flags |= TOTTY;
343 	}
344 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
345 	    (flags & TOCONS) && tp == constty)
346 		constty = NULL;
347 	if ((flags & TOLOG))
348 		msglogchar(c, NULL);
349 	if ((flags & TOCONS) && constty == NULL && c != '\0')
350 		(*v_putc)(c);
351 }
352 
353 /*
354  * Scaled down version of sprintf(3).
355  */
356 int
357 sprintf(char *buf, const char *cfmt, ...)
358 {
359 	int retval;
360 	va_list ap;
361 
362 	va_start(ap, cfmt);
363 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
364 	buf[retval] = '\0';
365 	va_end(ap);
366 	return retval;
367 }
368 
369 /*
370  * Put a number (base <= 16) in a buffer in reverse order; return an
371  * optional length and a pointer to the NULL terminated (preceded?)
372  * buffer.
373  */
374 static char *
375 ksprintn(ul, base, lenp)
376 	register u_long ul;
377 	register int base, *lenp;
378 {					/* A long in base 8, plus NULL. */
379 	static char buf[sizeof(long) * NBBY / 3 + 2];
380 	register char *p;
381 
382 	p = buf;
383 	do {
384 		*++p = hex2ascii(ul % base);
385 	} while (ul /= base);
386 	if (lenp)
387 		*lenp = p - buf;
388 	return (p);
389 }
390 
391 /*
392  * Scaled down version of printf(3).
393  *
394  * Two additional formats:
395  *
396  * The format %b is supported to decode error registers.
397  * Its usage is:
398  *
399  *	printf("reg=%b\n", regval, "<base><arg>*");
400  *
401  * where <base> is the output base expressed as a control character, e.g.
402  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
403  * the first of which gives the bit number to be inspected (origin 1), and
404  * the next characters (up to a control character, i.e. a character <= 32),
405  * give the name of the register.  Thus:
406  *
407  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
408  *
409  * would produce output:
410  *
411  *	reg=3<BITTWO,BITONE>
412  *
413  * XXX:  %D  -- Hexdump, takes pointer and separator string:
414  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
415  *		("%*D", len, ptr, " " -> XX XX XX XX ...
416  */
417 int
418 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
419 {
420 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
421 	char *p, *q, *d;
422 	u_char *up;
423 	int ch, n;
424 	u_long ul;
425 	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
426 	int dwidth;
427 	char padc;
428 	int retval = 0;
429 
430 	if (!func)
431 		d = (char *) arg;
432 	else
433 		d = NULL;
434 
435 	if (fmt == NULL)
436 		fmt = "(fmt null)\n";
437 
438 	if (radix < 2 || radix > 36)
439 		radix = 10;
440 
441 	for (;;) {
442 		padc = ' ';
443 		width = 0;
444 		while ((ch = *(u_char *)fmt++) != '%') {
445 			if (ch == '\0')
446 				return retval;
447 			PCHAR(ch);
448 		}
449 		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
450 		sign = 0; dot = 0; dwidth = 0;
451 reswitch:	switch (ch = *(u_char *)fmt++) {
452 		case '.':
453 			dot = 1;
454 			goto reswitch;
455 		case '#':
456 			sharpflag = 1;
457 			goto reswitch;
458 		case '+':
459 			sign = 1;
460 			goto reswitch;
461 		case '-':
462 			ladjust = 1;
463 			goto reswitch;
464 		case '%':
465 			PCHAR(ch);
466 			break;
467 		case '*':
468 			if (!dot) {
469 				width = va_arg(ap, int);
470 				if (width < 0) {
471 					ladjust = !ladjust;
472 					width = -width;
473 				}
474 			} else {
475 				dwidth = va_arg(ap, int);
476 			}
477 			goto reswitch;
478 		case '0':
479 			if (!dot) {
480 				padc = '0';
481 				goto reswitch;
482 			}
483 		case '1': case '2': case '3': case '4':
484 		case '5': case '6': case '7': case '8': case '9':
485 				for (n = 0;; ++fmt) {
486 					n = n * 10 + ch - '0';
487 					ch = *fmt;
488 					if (ch < '0' || ch > '9')
489 						break;
490 				}
491 			if (dot)
492 				dwidth = n;
493 			else
494 				width = n;
495 			goto reswitch;
496 		case 'b':
497 			ul = va_arg(ap, int);
498 			p = va_arg(ap, char *);
499 			for (q = ksprintn(ul, *p++, NULL); *q;)
500 				PCHAR(*q--);
501 
502 			if (!ul)
503 				break;
504 
505 			for (tmp = 0; *p;) {
506 				n = *p++;
507 				if (ul & (1 << (n - 1))) {
508 					PCHAR(tmp ? ',' : '<');
509 					for (; (n = *p) > ' '; ++p)
510 						PCHAR(n);
511 					tmp = 1;
512 				} else
513 					for (; *p > ' '; ++p)
514 						continue;
515 			}
516 			if (tmp)
517 				PCHAR('>');
518 			break;
519 		case 'c':
520 			PCHAR(va_arg(ap, int));
521 			break;
522 		case 'D':
523 			up = va_arg(ap, u_char *);
524 			p = va_arg(ap, char *);
525 			if (!width)
526 				width = 16;
527 			while(width--) {
528 				PCHAR(hex2ascii(*up >> 4));
529 				PCHAR(hex2ascii(*up & 0x0f));
530 				up++;
531 				if (width)
532 					for (q=p;*q;q++)
533 						PCHAR(*q);
534 			}
535 			break;
536 		case 'd':
537 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
538 			sign = 1;
539 			base = 10;
540 			goto number;
541 		case 'l':
542 			lflag = 1;
543 			goto reswitch;
544 		case 'n':
545 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
546 			base = radix;
547 			goto number;
548 		case 'o':
549 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
550 			base = 8;
551 			goto number;
552 		case 'p':
553 			ul = (u_long)va_arg(ap, void *);
554 			base = 16;
555 			PCHAR('0');
556 			PCHAR('x');
557 			goto number;
558 		case 's':
559 			p = va_arg(ap, char *);
560 			if (p == NULL)
561 				p = "(null)";
562 			if (!dot)
563 				n = strlen (p);
564 			else
565 				for (n = 0; n < dwidth && p[n]; n++)
566 					continue;
567 
568 			width -= n;
569 
570 			if (!ladjust && width > 0)
571 				while (width--)
572 					PCHAR(padc);
573 			while (n--)
574 				PCHAR(*p++);
575 			if (ladjust && width > 0)
576 				while (width--)
577 					PCHAR(padc);
578 			break;
579 		case 'u':
580 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
581 			base = 10;
582 			goto number;
583 		case 'x':
584 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
585 			base = 16;
586 number:			if (sign && (long)ul < 0L) {
587 				neg = 1;
588 				ul = -(long)ul;
589 			}
590 			p = ksprintn(ul, base, &tmp);
591 			if (sharpflag && ul != 0) {
592 				if (base == 8)
593 					tmp++;
594 				else if (base == 16)
595 					tmp += 2;
596 			}
597 			if (neg)
598 				tmp++;
599 
600 			if (!ladjust && width && (width -= tmp) > 0)
601 				while (width--)
602 					PCHAR(padc);
603 			if (neg)
604 				PCHAR('-');
605 			if (sharpflag && ul != 0) {
606 				if (base == 8) {
607 					PCHAR('0');
608 				} else if (base == 16) {
609 					PCHAR('0');
610 					PCHAR('x');
611 				}
612 			}
613 
614 			while (*p)
615 				PCHAR(*p--);
616 
617 			if (ladjust && width && (width -= tmp) > 0)
618 				while (width--)
619 					PCHAR(padc);
620 
621 			break;
622 		default:
623 			PCHAR('%');
624 			if (lflag)
625 				PCHAR('l');
626 			PCHAR(ch);
627 			break;
628 		}
629 	}
630 #undef PCHAR
631 }
632 
633 /*
634  * Put character in log buffer.
635  */
636 static void
637 msglogchar(int c, void *dummyarg)
638 {
639 	struct msgbuf *mbp;
640 
641 	if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
642 		mbp = msgbufp;
643 		if (mbp->msg_magic != MSG_MAGIC ||
644 		    mbp->msg_bufx >= MSG_BSIZE ||
645 		    mbp->msg_bufr >= MSG_BSIZE) {
646 			bzero(mbp, sizeof(struct msgbuf));
647 			mbp->msg_magic = MSG_MAGIC;
648 		}
649 		mbp->msg_bufc[mbp->msg_bufx++] = c;
650 		if (mbp->msg_bufx >= MSG_BSIZE)
651 			mbp->msg_bufx = 0;
652 		/* If the buffer is full, keep the most recent data. */
653 		if (mbp->msg_bufr == mbp->msg_bufx) {
654 			if (++mbp->msg_bufr >= MSG_BSIZE)
655 				mbp->msg_bufr = 0;
656 		}
657 	}
658 }
659