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