xref: /netbsd-src/sys/kern/subr_prf.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: subr_prf.c,v 1.18 1995/03/19 23:23:11 mycroft 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 /*
59  * Note that stdarg.h and the ANSI style va_start macro is used for both
60  * ANSI and traditional C compilers.
61  */
62 #include <machine/stdarg.h>
63 
64 #ifdef KADB
65 #include <machine/kdbparam.h>
66 #endif
67 
68 #define TOCONS	0x01
69 #define TOTTY	0x02
70 #define TOLOG	0x04
71 
72 struct	tty *constty;			/* pointer to console "window" tty */
73 
74 extern	cnputc();			/* standard console putc */
75 int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
76 
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 volatile void boot(int flags);	/* boot() does not return */
96 volatile			/* panic() does not return */
97 #endif
98 void
99 #ifdef __STDC__
100 panic(const char *fmt, ...)
101 #else
102 panic(fmt, va_alist)
103 	char *fmt;
104 #endif
105 {
106 	int bootopt;
107 	va_list ap;
108 
109 	bootopt = RB_AUTOBOOT | RB_DUMP;
110 	if (panicstr)
111 		bootopt |= RB_NOSYNC;
112 	else
113 		panicstr = fmt;
114 
115 	va_start(ap, fmt);
116 	printf("panic: %r\n", fmt, ap);
117 	va_end(ap);
118 
119 #ifdef KGDB
120 	kgdb_panic();
121 #endif
122 #ifdef KADB
123 	if (boothowto & RB_KDB)
124 		kdbpanic();
125 #endif
126 #ifdef DDB
127 	Debugger();
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 			if ((p = va_arg(ap, char *)) == NULL)
433 				p = "(null)";
434 			while (ch = *p++)
435 				putchar(ch, flags, tp);
436 			break;
437 		case 'd':
438 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
439 			if ((long)ul < 0) {
440 				putchar('-', flags, tp);
441 				ul = -(long)ul;
442 			}
443 			base = 10;
444 			goto number;
445 		case 'o':
446 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
447 			base = 8;
448 			goto number;
449 		case 'u':
450 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
451 			base = 10;
452 			goto number;
453 		case 'p':
454 			putchar('0', flags, tp);
455 			putchar('x', flags, tp);
456 			ul = (u_long)va_arg(ap, void *);
457 			base = 16;
458 			goto number;
459 		case 'x':
460 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
461 			base = 16;
462 number:			p = ksprintn(ul, base, &tmp);
463 			if (width && (width -= tmp) > 0)
464 				while (width--)
465 					putchar(padc, flags, tp);
466 			while (ch = *p--)
467 				putchar(ch, flags, tp);
468 			break;
469 		default:
470 			putchar('%', flags, tp);
471 			if (lflag)
472 				putchar('l', flags, tp);
473 			/* FALLTHROUGH */
474 		case '%':
475 			putchar(ch, flags, tp);
476 		}
477 	}
478 }
479 
480 /*
481  * Print a character on console or users terminal.  If destination is
482  * the console then the last MSGBUFS characters are saved in msgbuf for
483  * inspection later.
484  */
485 static void
486 putchar(c, flags, tp)
487 	register int c;
488 	int flags;
489 	struct tty *tp;
490 {
491 	extern int msgbufmapped;
492 	register struct msgbuf *mbp;
493 
494 	if (panicstr)
495 		constty = NULL;
496 	if ((flags & TOCONS) && tp == NULL && constty) {
497 		tp = constty;
498 		flags |= TOTTY;
499 	}
500 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
501 	    (flags & TOCONS) && tp == constty)
502 		constty = NULL;
503 	if ((flags & TOLOG) &&
504 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
505 		mbp = msgbufp;
506 		if (mbp->msg_magic != MSG_MAGIC) {
507 			bzero((caddr_t)mbp, sizeof(*mbp));
508 			mbp->msg_magic = MSG_MAGIC;
509 		}
510 		mbp->msg_bufc[mbp->msg_bufx++] = c;
511 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
512 			mbp->msg_bufx = 0;
513 	}
514 	if ((flags & TOCONS) && constty == NULL && c != '\0')
515 		(*v_putc)(c);
516 }
517 
518 /*
519  * Scaled down version of sprintf(3).
520  */
521 #ifdef __STDC__
522 sprintf(char *buf, const char *cfmt, ...)
523 #else
524 sprintf(buf, cfmt, va_alist)
525 	char *buf, *cfmt;
526 #endif
527 {
528 	register const char *fmt = cfmt;
529 	register char *p, *bp;
530 	register int ch, base;
531 	u_long ul;
532 	int lflag;
533 	va_list ap;
534 
535 	va_start(ap, cfmt);
536 	for (bp = buf; ; ) {
537 		while ((ch = *(u_char *)fmt++) != '%')
538 			if ((*bp++ = ch) == '\0')
539 				return ((bp - buf) - 1);
540 
541 		lflag = 0;
542 reswitch:	switch (ch = *(u_char *)fmt++) {
543 		case 'l':
544 			lflag = 1;
545 			goto reswitch;
546 		case 'c':
547 			*bp++ = va_arg(ap, int);
548 			break;
549 		case 's':
550 			p = va_arg(ap, char *);
551 			while (*bp++ = *p++)
552 				continue;
553 			--bp;
554 			break;
555 		case 'd':
556 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
557 			if ((long)ul < 0) {
558 				*bp++ = '-';
559 				ul = -(long)ul;
560 			}
561 			base = 10;
562 			goto number;
563 			break;
564 		case 'o':
565 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
566 			base = 8;
567 			goto number;
568 			break;
569 		case 'u':
570 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
571 			base = 10;
572 			goto number;
573 			break;
574 		case 'x':
575 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
576 			base = 16;
577 number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
578 				*bp++ = ch;
579 			break;
580 		default:
581 			*bp++ = '%';
582 			if (lflag)
583 				*bp++ = 'l';
584 			/* FALLTHROUGH */
585 		case '%':
586 			*bp++ = ch;
587 		}
588 	}
589 	va_end(ap);
590 }
591 
592 /*
593  * Put a number (base <= 16) in a buffer in reverse order; return an
594  * optional length and a pointer to the NULL terminated (preceded?)
595  * buffer.
596  */
597 static char *
598 ksprintn(ul, base, lenp)
599 	register u_long ul;
600 	register int base, *lenp;
601 {					/* A long in base 8, plus NULL. */
602 	static char buf[sizeof(long) * NBBY / 3 + 2];
603 	register char *p;
604 
605 	p = buf;
606 	do {
607 		*++p = "0123456789abcdef"[ul % base];
608 	} while (ul /= base);
609 	if (lenp)
610 		*lenp = p - buf;
611 	return (p);
612 }
613