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