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