xref: /csrg-svn/sys/kern/subr_prf.c (revision 41972)
1 /*
2  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)subr_prf.c	7.17 (Berkeley) 05/15/90
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "seg.h"
12 #include "buf.h"
13 #include "conf.h"
14 #include "reboot.h"
15 #include "vm.h"
16 #include "msgbuf.h"
17 #include "user.h"
18 #include "proc.h"
19 #include "ioctl.h"
20 #include "vnode.h"
21 #include "file.h"
22 #include "tty.h"
23 #include "syslog.h"
24 
25 #include "machine/mtpr.h"
26 #ifdef KADB
27 #include "machine/kdbparam.h"
28 #endif
29 
30 #define TOCONS	0x1
31 #define TOTTY	0x2
32 #define TOLOG	0x4
33 
34 /*
35  * In case console is off,
36  * panicstr contains argument to last
37  * call to panic.
38  */
39 char	*panicstr;
40 
41 extern	cnputc();			/* standard console putc */
42 int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
43 extern	struct tty cons;		/* standard console tty */
44 struct	tty *constty;			/* pointer to console "window" tty */
45 
46 #ifdef KADB
47 extern	cngetc();			/* standard console getc */
48 extern	cnpoll();
49 int	(*v_getc)() = cngetc;		/* "" getc from virtual console */
50 int	(*v_poll)() = cnpoll;		/* kdb hook to enable input polling */
51 #endif
52 
53 /*
54  * Scaled down version of C Library printf.
55  * Used to print diagnostic information directly on console tty.
56  * Since it is not interrupt driven, all system activities are
57  * suspended.  Printf should not be used for chit-chat.
58  *
59  * One additional format: %b is supported to decode error registers.
60  * Usage is:
61  *	printf("reg=%b\n", regval, "<base><arg>*");
62  * Where <base> is the output base expressed as a control character,
63  * e.g. \10 gives octal; \20 gives hex.  Each arg is a sequence of
64  * characters, the first of which gives the bit number to be inspected
65  * (origin 1), and the next characters (up to a control character, i.e.
66  * a character <= 32), give the name of the register.  Thus
67  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
68  * would produce output:
69  *	reg=3<BITTWO,BITONE>
70  *
71  * Another additional format: %r is used to pass an additional format string
72  * and argument list recursively.  Usage is typically:
73  *
74  * fn(otherstuff, fmt [, arg1, ... ] )
75  *	char *fmt;
76  *	u_int arg1, ...;
77  *
78  *	printf("prefix: %r, other stuff\n", fmt, &arg1);
79  */
80 #if defined(tahoe)
81 int	consintr;
82 #endif
83 
84 /*VARARGS1*/
85 printf(fmt, x1)
86 	char *fmt;
87 	unsigned x1;
88 {
89 #if defined(tahoe)
90 	register int savintr;
91 
92 	savintr = consintr, consintr = 0;	/* disable interrupts */
93 #endif
94 	prf(fmt, &x1, TOCONS | TOLOG, (caddr_t)0);
95 	if (!panicstr)
96 		logwakeup();
97 #if defined(tahoe)
98 	consintr = savintr;			/* reenable interrupts */
99 #endif
100 }
101 
102 /*
103  * Uprintf prints to the controlling terminal for the current process.
104  * It may block if the tty queue is overfull.
105  * No message is printed if the queue does not clear
106  * in a reasonable time.
107  */
108 /*VARARGS1*/
109 uprintf(fmt, x1)
110 	char *fmt;
111 	unsigned x1;
112 {
113 	register struct tty *tp = u.u_procp->p_session->s_ttyp;
114 
115 	if (tp != NULL && tp->t_session == u.u_procp->p_session)
116 		prf(fmt, &x1, TOTTY, (caddr_t)tp);
117 }
118 
119 /*
120  * tprintf prints on the specified terminal (console if none)
121  * and logs the message.  It is designed for error messages from
122  * single-open devices, and may be called from interrupt level
123  * (does not sleep).
124  */
125 /*VARARGS2*/
126 tprintf(vp, fmt, x1)
127 	register caddr_t vp;
128 	char *fmt;
129 	unsigned x1;
130 {
131 #ifdef notyet
132 	int flags = TOTTY | TOLOG;
133 
134 	logpri(LOG_INFO);
135 
136 	if (vp == NULL ||
137 	    VOP_IOCTL(vp, TIOCCHECKOUTQ, &val, FWRITE, NOCRED) != 0 ||
138 	    val == 0)
139 		flags = TOLOG;
140 	prf(fmt, &x1, flags, vp);
141 	logwakeup();
142 #else
143 	printf("tprintf called\n");
144 #endif
145 }
146 
147 /*
148  * Log writes to the log buffer,
149  * and guarantees not to sleep (so can be called by interrupt routines).
150  * If there is no process reading the log yet, it writes to the console also.
151  */
152 /*VARARGS2*/
153 log(level, fmt, x1)
154 	char *fmt;
155 	unsigned x1;
156 {
157 	register s = splhigh();
158 	extern int log_open;
159 
160 	logpri(level);
161 	prf(fmt, &x1, TOLOG, (caddr_t)0);
162 	splx(s);
163 	if (!log_open)
164 		prf(fmt, &x1, TOCONS, (caddr_t)0);
165 	logwakeup();
166 }
167 
168 logpri(level)
169 	int level;
170 {
171 
172 	putchar('<', TOLOG, (caddr_t)0);
173 	printn((u_long)level, 10, TOLOG, (caddr_t)0);
174 	putchar('>', TOLOG, (caddr_t)0);
175 }
176 
177 /*VARARGS1*/
178 addlog(fmt, x1)
179 	char *fmt;
180 	unsigned x1;
181 {
182 	register s = splhigh();
183 
184 	prf(fmt, &x1, TOLOG, (caddr_t)0);
185 	splx(s);
186 	if (!log_open)
187 		prf(fmt, &x1, TOCONS, (caddr_t)0);
188 	logwakeup();
189 }
190 
191 prf(fmt, adx, flags, where)
192 	register char *fmt;
193 	register u_int *adx;
194 	caddr_t where;
195 {
196 	register int b, c, i;
197 	char *s;
198 	int any;
199 
200 loop:
201 	while ((c = *fmt++) != '%') {
202 		if (c == '\0')
203 			return;
204 		putchar(c, flags, where);
205 	}
206 again:
207 	c = *fmt++;
208 	/* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */
209 	switch (c) {
210 
211 	case 'l':
212 		goto again;
213 	case 'x': case 'X':
214 		b = 16;
215 		goto number;
216 	case 'd': case 'D':
217 		b = -10;
218 		goto number;
219 	case 'u':
220 		b = 10;
221 		goto number;
222 	case 'o': case 'O':
223 		b = 8;
224 number:
225 		printn((u_long)*adx, b, flags, where);
226 		break;
227 	case 'c':
228 		b = *adx;
229 #if BYTE_ORDER == LITTLE_ENDIAN
230 		for (i = 24; i >= 0; i -= 8)
231 			if (c = (b >> i) & 0x7f)
232 				putchar(c, flags, where);
233 #endif
234 #if BYTE_ORDER == BIG_ENDIAN
235 		if (c = (b & 0x7f))
236 			putchar(c, flags, where);
237 #endif
238 		break;
239 	case 'b':
240 		b = *adx++;
241 		s = (char *)*adx;
242 		printn((u_long)b, *s++, flags, where);
243 		any = 0;
244 		if (b) {
245 			while (i = *s++) {
246 				if (b & (1 << (i-1))) {
247 					putchar(any ? ',' : '<', flags, where);
248 					any = 1;
249 					for (; (c = *s) > 32; s++)
250 						putchar(c, flags, where);
251 				} else
252 					for (; *s > 32; s++)
253 						;
254 			}
255 			if (any)
256 				putchar('>', flags, where);
257 		}
258 		break;
259 
260 	case 's':
261 		s = (char *)*adx;
262 		while (c = *s++)
263 			putchar(c, flags, where);
264 		break;
265 
266 	case 'r':
267 		s = (char *)*adx++;
268 		prf(s, (u_int *)*adx, flags, where);
269 		break;
270 
271 	case '%':
272 		putchar('%', flags, where);
273 		break;
274 	}
275 	adx++;
276 	goto loop;
277 }
278 
279 /*
280  * Printn prints a number n in base b.
281  * We don't use recursion to avoid deep kernel stacks.
282  */
283 printn(n, b, flags, where)
284 	u_long n;
285 	caddr_t where;
286 {
287 	char prbuf[11];
288 	register char *cp;
289 
290 	if (b == -10) {
291 		if ((int)n < 0) {
292 			putchar('-', flags, where);
293 			n = (unsigned)(-(int)n);
294 		}
295 		b = -b;
296 	}
297 	cp = prbuf;
298 	do {
299 		*cp++ = "0123456789abcdef"[n%b];
300 		n /= b;
301 	} while (n);
302 	do
303 		putchar(*--cp, flags, where);
304 	while (cp > prbuf);
305 }
306 
307 /*
308  * Panic is called on unresolvable fatal errors.
309  * It prints "panic: mesg", and then reboots.
310  * If we are called twice, then we avoid trying to
311  * sync the disks as this often leads to recursive panics.
312  */
313 panic(s)
314 	char *s;
315 {
316 	int bootopt = RB_AUTOBOOT | RB_DUMP;
317 
318 	if (panicstr)
319 		bootopt |= RB_NOSYNC;
320 	else {
321 		panicstr = s;
322 	}
323 	printf("panic: %s\n", s);
324 #ifdef KADB
325 	if (boothowto & RB_KDB) {
326 		int x = splnet();	/* below kdb pri */
327 
328 		setsoftkdb();
329 		splx(x);
330 	}
331 #endif
332 	boot(bootopt);
333 }
334 
335 /*
336  * Warn that a system table is full.
337  */
338 tablefull(tab)
339 	char *tab;
340 {
341 
342 	log(LOG_ERR, "%s: table is full\n", tab);
343 }
344 
345 /*
346  * Print a character on console or users terminal.
347  * If destination is console then the last MSGBUFS characters
348  * are saved in msgbuf for inspection later.
349  */
350 /*ARGSUSED*/
351 putchar(c, flags, where)
352 	register int c;
353 	caddr_t where;
354 {
355 	extern int msgbufmapped;
356 
357 	if (panicstr)
358 		constty = 0;
359 	if ((flags & TOCONS) && where == 0 && constty) {
360 		where = (caddr_t)constty;
361 		flags |= TOTTY;
362 	}
363 	if ((flags & TOTTY) && where && tputchar(c, (struct tty *)where) < 0 &&
364 	    (flags & TOCONS) && (struct tty *)where == constty)
365 		constty = 0;
366 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 &&
367 	    msgbufmapped) {
368 		if (msgbuf.msg_magic != MSG_MAGIC) {
369 			register int i;
370 
371 			msgbuf.msg_magic = MSG_MAGIC;
372 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
373 			for (i=0; i < MSG_BSIZE; i++)
374 				msgbuf.msg_bufc[i] = 0;
375 		}
376 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
377 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
378 			msgbuf.msg_bufx = 0;
379 	}
380 	if ((flags & TOCONS) && constty == 0 && c != '\0')
381 		(*v_putc)(c);
382 }
383