xref: /original-bsd/sys/kern/subr_prf.c (revision 11cb310b)
1 /*-
2  * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)subr_prf.c	7.22 (Berkeley) 05/04/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "buf.h"
13 #include "conf.h"
14 #include "reboot.h"
15 #include "msgbuf.h"
16 #include "proc.h"
17 #include "ioctl.h"
18 #include "vnode.h"
19 #include "file.h"
20 #include "tty.h"
21 #include "tprintf.h"
22 #include "syslog.h"
23 #include "malloc.h"
24 
25 /*
26  * Note that stdarg.h and the ANSI style va_start macro is used for both
27  * ANSI and traditional C compilers.
28  */
29 #include <machine/stdarg.h>
30 
31 #ifdef KADB
32 #include "machine/kdbparam.h"
33 #endif
34 
35 #define TOCONS	0x01
36 #define TOTTY	0x02
37 #define TOLOG	0x04
38 
39 struct	tty *constty;			/* pointer to console "window" tty */
40 
41 #ifdef KADB
42 extern	cngetc();			/* standard console getc */
43 int	(*v_getc)() = cngetc;		/* "" getc from virtual console */
44 extern	cnpoll();
45 int	(*v_poll)() = cnpoll;		/* kdb hook to enable input polling */
46 #endif
47 extern	cnputc();			/* standard console putc */
48 int	(*v_putc)() = cnputc;          	/* routine to putc on virtual console */
49 
50 static void logpri __P((int));
51 static void putchar __P((int, int, struct tty *));
52 static void kprintf __P((const char *, int, struct tty *, ...));
53 static void kprintn __P((u_long, int));
54 
55 /*
56  * Variable panicstr contains argument to first call to panic; used
57  * as flag to indicate that the kernel has already called panic.
58  */
59 char	*panicstr;
60 
61 /*
62  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
63  * and then reboots.  If we are called twice, then we avoid trying to sync
64  * the disks as this often leads to recursive panics.
65  */
66 void
67 panic(msg)
68 	char *msg;
69 {
70 	int bootopt = RB_AUTOBOOT | RB_DUMP;
71 	int s;
72 
73 	if (panicstr)
74 		bootopt |= RB_NOSYNC;
75 	else
76 		panicstr = msg;
77 	printf("panic: %s\n", msg);
78 #ifdef KGDB
79 	kgdb_panic();
80 #endif
81 #ifdef KADB
82 	if (boothowto & RB_KDB) {
83 		s = splnet();		/* below kdb pri */
84 		setsoftkdb();
85 		splx(s);
86 	}
87 #endif
88 	boot(bootopt);
89 }
90 
91 /*
92  * Warn that a system table is full.
93  */
94 void
95 tablefull(tab)
96 	char *tab;
97 {
98 
99 	log(LOG_ERR, "%s: table is full\n", tab);
100 }
101 
102 /*
103  * Uprintf prints to the controlling terminal for the current process.
104  * It may block if the tty queue is overfull.  No message is printed if
105  * the queue does not clear in a reasonable time.
106  */
107 void
108 #ifdef __STDC__
109 uprintf(const char *fmt, ...)
110 #else
111 uprintf(fmt /*, va_alist */)
112 	char *fmt;
113 #endif
114 {
115 	register struct proc *p = curproc;
116 	va_list ap;
117 
118 	va_start(ap, fmt);
119 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp)
120 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
121 	va_end(ap);
122 }
123 
124 tpr_t
125 tprintf_open(p)
126 	register struct proc *p;
127 {
128 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
129 		SESSHOLD(p->p_session);
130 		return ((tpr_t) p->p_session);
131 	}
132 	return ((tpr_t) NULL);
133 }
134 
135 void
136 tprintf_close(sess)
137 	tpr_t sess;
138 {
139 	if (sess)
140 		SESSRELE((struct session *) sess);
141 }
142 
143 /*
144  * tprintf prints on the controlling terminal associated
145  * with the given session.
146  */
147 void
148 #ifdef __STDC__
149 tprintf(tpr_t tpr, const char *fmt, ...)
150 #else
151 tprintf(tpr, fmt /*, va_alist */)
152 	tpr_t tpr;
153 	char *fmt;
154 #endif
155 {
156 	register struct session *sess = (struct session *)tpr;
157 	struct tty *tp = NULL;
158 	int flags = TOLOG;
159 	va_list ap;
160 
161 	logpri(LOG_INFO);
162 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
163 		flags |= TOTTY;
164 		tp = sess->s_ttyp;
165 	}
166 	va_start(ap, fmt);
167 	kprintf(fmt, flags, tp, ap);
168 	va_end(ap);
169 	logwakeup();
170 }
171 
172 /*
173  * Ttyprintf displays a message on a tty; it should be used only by
174  * the tty driver, or anything that knows the underlying tty will not
175  * be revoke(2)'d away.  Other callers should use tprintf.
176  */
177 void
178 #ifdef __STDC__
179 ttyprintf(struct tty *tp, const char *fmt, ...)
180 #else
181 ttyprintf(tp, fmt /*, va_alist */)
182 	struct tty *tp;
183 	char *fmt;
184 #endif
185 {
186 	va_list ap;
187 
188 	va_start(ap, fmt);
189 	kprintf(fmt, TOTTY, tp, ap);
190 	va_end(ap);
191 }
192 
193 extern	int log_open;
194 
195 /*
196  * Log writes to the log buffer, and guarantees not to sleep (so can be
197  * called by interrupt routines).  If there is no process reading the
198  * log yet, it writes to the console also.
199  */
200 void
201 #ifdef __STDC__
202 log(int level, const char *fmt, ...)
203 #else
204 log(level, fmt /*, va_alist */)
205 	int level;
206 	char *fmt;
207 #endif
208 {
209 	register s = splhigh();
210 	va_list ap;
211 
212 	logpri(level);
213 	va_start(ap, fmt);
214 	kprintf(fmt, TOLOG, NULL, ap);
215 	splx(s);
216 	if (!log_open)
217 		kprintf(fmt, TOCONS, NULL, ap);
218 	va_end(ap);
219 	logwakeup();
220 }
221 
222 static void
223 logpri(level)
224 	int level;
225 {
226 
227 	putchar('<', TOLOG, NULL);
228 	kprintn((u_long)level, 10, TOLOG, NULL);
229 	putchar('>', TOLOG, NULL);
230 }
231 
232 void
233 #ifdef __STDC__
234 addlog(const char *fmt, ...)
235 #else
236 addlog(fmt /*, va_alist */)
237 	char *fmt;
238 #endif
239 {
240 	register s = splhigh();
241 	va_list ap;
242 
243 	va_start(ap, fmt);
244 	kprintf(fmt, TOLOG, NULL, ap);
245 	splx(s);
246 	if (!log_open)
247 		kprintf(fmt, TOCONS, NULL, ap);
248 	va_end(ap);
249 	logwakeup();
250 }
251 
252 int	consintr = 1;			/* ok to handle console interrupts? */
253 
254 void
255 #ifdef __STDC__
256 printf(const char *fmt, ...)
257 #else
258 printf(fmt /*, va_alist */)
259 	char *fmt;
260 #endif
261 {
262 	register int savintr;
263 	va_list ap;
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  *	kprintf("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  *	kprintf("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, fmt [, arg1, ... ])
302  *	char *fmt;
303  *	u_int arg1, ...;
304  *
305  *	kprintf("prefix: %r, other stuff\n", fmt, ap);
306  */
307 static void
308 kprintf(fmt, flags, ttyp, ap)
309 	register char *fmt;
310 	int flags;
311 	struct tty *ttyp;
312 	va_list ap;
313 {
314 	register char *p;
315 	register int ch, n;
316 	unsigned long ul;
317 	int lflag, set;
318 
319 	for (;;) {
320 		while ((ch = *fmt++) != '%') {
321 			if (ch == '\0')
322 				return;
323 			putchar(ch, flags, ttyp);
324 		}
325 		lflag = 0;
326 reswitch:	switch (ch = *fmt++) {
327 		case 'l':
328 			lflag = 1;
329 			goto reswitch;
330 		case 'b':
331 			ul = va_arg(ap, int);
332 			p = va_arg(ap, char *);
333 			kprintn(ul, *p++);
334 
335 			if (!ul)
336 				break;
337 
338 			for (set = 0; n = *p++;) {
339 				if (ul & (1 << (n - 1))) {
340 					putchar(set ? ',' : '<', flags, ttyp);
341 					for (; (n = *p) > ' '; ++p)
342 						putchar(n, flags, ttyp);
343 					set = 1;
344 				} else
345 					for (; *p > ' '; ++p);
346 			}
347 			if (set)
348 				putchar('>', flags, ttyp);
349 			break;
350 		case 'c':
351 			putchar(va_arg(ap, int), flags, ttyp);
352 			break;
353 		case 'r':
354 			p = va_arg(ap, char *);
355 			kprintf(p, flags, ttyp, va_arg(ap, va_list));
356 			break;
357 		case 's':
358 			p = va_arg(ap, char *);
359 			while (ch = *p++)
360 				putchar(ch, flags, ttyp);
361 			break;
362 		case 'D':
363 			lflag = 1;
364 			/* FALLTHROUGH */
365 		case 'd':
366 			ul = lflag ?
367 			    va_arg(ap, long) : va_arg(ap, int);
368 			if ((long)ul < 0) {
369 				putchar('-', flags, ttyp);
370 				ul = -(long)ul;
371 			}
372 			kprintn(ul, 10);
373 			break;
374 		case 'O':
375 			lflag = 1;
376 			/* FALLTHROUGH */
377 		case 'o':
378 			ul = lflag ?
379 			    va_arg(ap, u_long) : va_arg(ap, u_int);
380 			kprintn(ul, 8);
381 			break;
382 		case 'U':
383 			lflag = 1;
384 			/* FALLTHROUGH */
385 		case 'u':
386 			ul = lflag ?
387 			    va_arg(ap, u_long) : va_arg(ap, u_int);
388 			kprintn(ul, 10);
389 			break;
390 		case 'X':
391 			lflag = 1;
392 			/* FALLTHROUGH */
393 		case 'x':
394 			ul = lflag ?
395 			    va_arg(ap, u_long) : va_arg(ap, u_int);
396 			kprintn(ul, 16);
397 			break;
398 		default:
399 			putchar('%', flags, ttyp);
400 			if (lflag)
401 				putchar('l', flags, ttyp);
402 			putchar(ch, flags, ttyp);
403 		}
404 	}
405 	va_end(ap);
406 }
407 
408 static void
409 kprintn(ul, base)
410 	u_long ul;
411 	int base;
412 {
413 					/* hold a long in base 8 */
414 	char *p, buf[(sizeof(long) * NBBY >> 3) + 1];
415 
416 	p = buf;
417 	do {
418 		*p++ = "0123456789abcdef"[ul % base];
419 	} while (ul /= base);
420 	do {
421 		putchar(*--p);
422 	} while (p > buf);
423 }
424 
425 /*
426  * Print a character on console or users terminal.  If destination is
427  * the console then the last MSGBUFS characters are saved in msgbuf for
428  * inspection later.
429  */
430 static void
431 putchar(c, flags, ttyp)
432 	register int c;
433 	int flags;
434 	struct tty *ttyp;
435 {
436 	extern int msgbufmapped;
437 	register struct msgbuf *mbp;
438 
439 	if (panicstr)
440 		constty = NULL;
441 	if ((flags & TOCONS) && ttyp == NULL && constty) {
442 		ttyp = constty;
443 		flags |= TOTTY;
444 	}
445 	if ((flags & TOTTY) && ttyp && tputchar(c, ttyp) < 0 &&
446 	    (flags & TOCONS) && ttyp == constty)
447 		constty = NULL;
448 	if ((flags & TOLOG) &&
449 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
450  		mbp = msgbufp;
451 		if (mbp->msg_magic != MSG_MAGIC) {
452 			register int i;
453 
454 			mbp->msg_magic = MSG_MAGIC;
455 			mbp->msg_bufx = mbp->msg_bufr = 0;
456 			for (i = 0; i < MSG_BSIZE; i++)
457 				mbp->msg_bufc[i] = 0;
458 		}
459 		mbp->msg_bufc[mbp->msg_bufx++] = c;
460 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
461 			mbp->msg_bufx = 0;
462 	}
463 	if ((flags & TOCONS) && constty == NULL && c != '\0')
464 		(*v_putc)(c);
465 }
466