xref: /csrg-svn/sys/kern/subr_prf.c (revision 40808)
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.16 (Berkeley) 04/05/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 	logwakeup();
96 #if defined(tahoe)
97 	consintr = savintr;			/* reenable interrupts */
98 #endif
99 }
100 
101 /*
102  * Uprintf prints to the controlling terminal for the current process.
103  * It may block if the tty queue is overfull.
104  * No message is printed if the queue does not clear
105  * in a reasonable time.
106  */
107 /*VARARGS1*/
108 uprintf(fmt, x1)
109 	char *fmt;
110 	unsigned x1;
111 {
112 	register struct tty *tp = u.u_procp->p_session->s_ttyp;
113 
114 	if (tp != NULL && tp->t_session == u.u_procp->p_session)
115 		prf(fmt, &x1, TOTTY, tp);
116 }
117 
118 /*
119  * tprintf prints on the specified terminal (console if none)
120  * and logs the message.  It is designed for error messages from
121  * single-open devices, and may be called from interrupt level
122  * (does not sleep).
123  */
124 /*VARARGS2*/
125 tprintf(vp, fmt, x1)
126 	register caddr_t vp;
127 	char *fmt;
128 	unsigned x1;
129 {
130 	int flags = TOTTY | TOLOG;
131 
132 #ifdef notyet
133 	logpri(LOG_INFO);
134 
135 	if (vp == NULL ||
136 	    VOP_IOCTL(vp, TIOCCHECKOUTQ, &val, FWRITE, NOCRED) != 0 ||
137 	    val == 0)
138 		flags = TOLOG;
139 	prf(fmt, &x1, flags, vp);
140 	logwakeup();
141 #else
142 	printf("tprintf called\n");
143 #endif
144 }
145 
146 /*
147  * Log writes to the log buffer,
148  * and guarantees not to sleep (so can be called by interrupt routines).
149  * If there is no process reading the log yet, it writes to the console also.
150  */
151 /*VARARGS2*/
152 log(level, fmt, x1)
153 	char *fmt;
154 	unsigned x1;
155 {
156 	register s = splhigh();
157 	extern int log_open;
158 
159 	logpri(level);
160 	prf(fmt, &x1, TOLOG, (caddr_t)0);
161 	splx(s);
162 	if (!log_open)
163 		prf(fmt, &x1, TOCONS, (caddr_t)0);
164 	logwakeup();
165 }
166 
167 logpri(level)
168 	int level;
169 {
170 
171 	putchar('<', TOLOG, (struct tty *)0);
172 	printn((u_long)level, 10, TOLOG, (struct tty *)0);
173 	putchar('>', TOLOG, (struct tty *)0);
174 }
175 
176 /*VARARGS1*/
177 addlog(fmt, x1)
178 	char *fmt;
179 	unsigned x1;
180 {
181 	register s = splhigh();
182 
183 	prf(fmt, &x1, TOLOG, (caddr_t)0);
184 	splx(s);
185 	if (!log_open)
186 		prf(fmt, &x1, TOCONS, (caddr_t)0);
187 	logwakeup();
188 }
189 
190 prf(fmt, adx, flags, where)
191 	register char *fmt;
192 	register u_int *adx;
193 	caddr_t where;
194 {
195 	register int b, c, i;
196 	char *s;
197 	int any;
198 
199 loop:
200 	while ((c = *fmt++) != '%') {
201 		if (c == '\0')
202 			return;
203 		putchar(c, flags, where);
204 	}
205 again:
206 	c = *fmt++;
207 	/* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */
208 	switch (c) {
209 
210 	case 'l':
211 		goto again;
212 	case 'x': case 'X':
213 		b = 16;
214 		goto number;
215 	case 'd': case 'D':
216 		b = -10;
217 		goto number;
218 	case 'u':
219 		b = 10;
220 		goto number;
221 	case 'o': case 'O':
222 		b = 8;
223 number:
224 		printn((u_long)*adx, b, flags, where);
225 		break;
226 	case 'c':
227 		b = *adx;
228 #if BYTE_ORDER == LITTLE_ENDIAN
229 		for (i = 24; i >= 0; i -= 8)
230 			if (c = (b >> i) & 0x7f)
231 				putchar(c, flags, where);
232 #endif
233 #if BYTE_ORDER == BIG_ENDIAN
234 		if (c = (b & 0x7f))
235 			putchar(c, flags, where);
236 #endif
237 		break;
238 	case 'b':
239 		b = *adx++;
240 		s = (char *)*adx;
241 		printn((u_long)b, *s++, flags, where);
242 		any = 0;
243 		if (b) {
244 			while (i = *s++) {
245 				if (b & (1 << (i-1))) {
246 					putchar(any ? ',' : '<', flags, where);
247 					any = 1;
248 					for (; (c = *s) > 32; s++)
249 						putchar(c, flags, where);
250 				} else
251 					for (; *s > 32; s++)
252 						;
253 			}
254 			if (any)
255 				putchar('>', flags, where);
256 		}
257 		break;
258 
259 	case 's':
260 		s = (char *)*adx;
261 		while (c = *s++)
262 			putchar(c, flags, where);
263 		break;
264 
265 	case 'r':
266 		s = (char *)*adx++;
267 		prf(s, (u_int *)*adx, flags, where);
268 		break;
269 
270 	case '%':
271 		putchar('%', flags, where);
272 		break;
273 	}
274 	adx++;
275 	goto loop;
276 }
277 
278 /*
279  * Printn prints a number n in base b.
280  * We don't use recursion to avoid deep kernel stacks.
281  */
282 printn(n, b, flags, where)
283 	u_long n;
284 	caddr_t where;
285 {
286 	char prbuf[11];
287 	register char *cp;
288 
289 	if (b == -10) {
290 		if ((int)n < 0) {
291 			putchar('-', flags, where);
292 			n = (unsigned)(-(int)n);
293 		}
294 		b = -b;
295 	}
296 	cp = prbuf;
297 	do {
298 		*cp++ = "0123456789abcdef"[n%b];
299 		n /= b;
300 	} while (n);
301 	do
302 		putchar(*--cp, flags, where);
303 	while (cp > prbuf);
304 }
305 
306 /*
307  * Panic is called on unresolvable fatal errors.
308  * It prints "panic: mesg", and then reboots.
309  * If we are called twice, then we avoid trying to
310  * sync the disks as this often leads to recursive panics.
311  */
312 panic(s)
313 	char *s;
314 {
315 	int bootopt = RB_AUTOBOOT | RB_DUMP;
316 
317 	if (panicstr)
318 		bootopt |= RB_NOSYNC;
319 	else {
320 		panicstr = s;
321 	}
322 	printf("panic: %s\n", s);
323 #ifdef KADB
324 	if (boothowto & RB_KDB) {
325 		int x = splnet();	/* below kdb pri */
326 
327 		setsoftkdb();
328 		splx(x);
329 	}
330 #endif
331 	boot(bootopt);
332 }
333 
334 /*
335  * Warn that a system table is full.
336  */
337 tablefull(tab)
338 	char *tab;
339 {
340 
341 	log(LOG_ERR, "%s: table is full\n", tab);
342 }
343 
344 /*
345  * Print a character on console or users terminal.
346  * If destination is console then the last MSGBUFS characters
347  * are saved in msgbuf for inspection later.
348  */
349 /*ARGSUSED*/
350 putchar(c, flags, where)
351 	register int c;
352 	caddr_t where;
353 {
354 	extern int msgbufmapped;
355 
356 	if (panicstr)
357 		constty = 0;
358 	if ((flags & TOCONS) && where == 0 && constty) {
359 		where = (caddr_t)constty;
360 		flags |= TOTTY;
361 	}
362 	if ((flags & TOTTY) && where && tputchar(c, (struct tty *)where) < 0 &&
363 	    (flags & TOCONS) && (struct tty *)where == constty)
364 		constty = 0;
365 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 &&
366 	    msgbufmapped) {
367 		if (msgbuf.msg_magic != MSG_MAGIC) {
368 			register int i;
369 
370 			msgbuf.msg_magic = MSG_MAGIC;
371 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
372 			for (i=0; i < MSG_BSIZE; i++)
373 				msgbuf.msg_bufc[i] = 0;
374 		}
375 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
376 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
377 			msgbuf.msg_bufx = 0;
378 	}
379 	if ((flags & TOCONS) && constty == 0 && c != '\0')
380 		(*v_putc)(c);
381 }
382