xref: /csrg-svn/sys/kern/subr_prf.c (revision 29946)
1 /*
2  * Copyright (c) 1982, 1986 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.3 (Berkeley) 11/03/86
7  */
8 #include "../machine/mtpr.h"
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "seg.h"
13 #include "buf.h"
14 #include "conf.h"
15 #include "reboot.h"
16 #include "vm.h"
17 #include "msgbuf.h"
18 #include "dir.h"
19 #include "user.h"
20 #include "proc.h"
21 #include "ioctl.h"
22 #include "tty.h"
23 #include "syslog.h"
24 
25 #define TOCONS	0x1
26 #define TOTTY	0x2
27 #define TOLOG	0x4
28 
29 /*
30  * In case console is off,
31  * panicstr contains argument to last
32  * call to panic.
33  */
34 char	*panicstr;
35 
36 /*
37  * Scaled down version of C Library printf.
38  * Used to print diagnostic information directly on console tty.
39  * Since it is not interrupt driven, all system activities are
40  * suspended.  Printf should not be used for chit-chat.
41  *
42  * One additional format: %b is supported to decode error registers.
43  * Usage is:
44  *	printf("reg=%b\n", regval, "<base><arg>*");
45  * Where <base> is the output base expressed as a control character,
46  * e.g. \10 gives octal; \20 gives hex.  Each arg is a sequence of
47  * characters, the first of which gives the bit number to be inspected
48  * (origin 1), and the next characters (up to a control character, i.e.
49  * a character <= 32), give the name of the register.  Thus
50  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
51  * would produce output:
52  *	reg=3<BITTWO,BITONE>
53  */
54 #if defined(tahoe)
55 int	consintr;
56 #endif
57 
58 /*VARARGS1*/
59 printf(fmt, x1)
60 	char *fmt;
61 	unsigned x1;
62 {
63 #if defined(tahoe)
64 	register int savintr;
65 
66 	savintr = consintr, consintr = 0;	/* disable interrupts */
67 #endif
68 	prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0);
69 	logwakeup();
70 #if defined(tahoe)
71 	consintr = savintr;			/* reenable interrupts */
72 #endif
73 }
74 
75 /*
76  * Uprintf prints to the current user's terminal.
77  * It may block if the tty queue is overfull.
78  * Should determine whether current terminal user is related
79  * to this process.
80  */
81 /*VARARGS1*/
82 uprintf(fmt, x1)
83 	char *fmt;
84 	unsigned x1;
85 {
86 #ifdef notdef
87 	register struct proc *p;
88 #endif
89 	register struct tty *tp;
90 
91 	if ((tp = u.u_ttyp) == NULL)
92 		return;
93 #ifdef notdef
94 	if (tp->t_pgrp && (p = pfind(tp->t_pgrp)))
95 		if (p->p_uid != u.u_uid)	/* doesn't account for setuid */
96 			return;
97 #endif
98 	(void)ttycheckoutq(tp, 1);
99 	prf(fmt, &x1, TOTTY, tp);
100 }
101 
102 /*
103  * tprintf prints on the specified terminal (console if none)
104  * and logs the message.  It is designed for error messages from
105  * single-open devices, and may be called from interrupt level
106  * (does not sleep).
107  */
108 /*VARARGS2*/
109 tprintf(tp, fmt, x1)
110 	register struct tty *tp;
111 	char *fmt;
112 	unsigned x1;
113 {
114 	int flags = TOTTY | TOLOG;
115 	extern struct tty cons;
116 
117 	logpri(LOG_INFO);
118 	if (tp == (struct tty *)NULL)
119 		tp = &cons;
120 	if (ttycheckoutq(tp, 0) == 0)
121 		flags = TOLOG;
122 	prf(fmt, &x1, flags, tp);
123 	logwakeup();
124 }
125 
126 /*
127  * Log writes to the log buffer,
128  * and guarantees not to sleep (so can be called by interrupt routines).
129  * If there is no process reading the log yet, it writes to the console also.
130  */
131 /*VARARGS2*/
132 log(level, fmt, x1)
133 	char *fmt;
134 	unsigned x1;
135 {
136 	register s = splhigh();
137 	extern int log_open;
138 
139 	logpri(level);
140 	prf(fmt, &x1, TOLOG, (struct tty *)0);
141 	splx(s);
142 	if (!log_open)
143 		prf(fmt, &x1, TOCONS, (struct tty *)0);
144 	logwakeup();
145 }
146 
147 logpri(level)
148 	int level;
149 {
150 
151 	putchar('<', TOLOG, (struct tty *)0);
152 	printn((u_long)level, 10, TOLOG, (struct tty *)0);
153 	putchar('>', TOLOG, (struct tty *)0);
154 }
155 
156 prf(fmt, adx, flags, ttyp)
157 	register char *fmt;
158 	register u_int *adx;
159 	struct tty *ttyp;
160 {
161 	register int b, c, i;
162 	char *s;
163 	int any;
164 
165 loop:
166 	while ((c = *fmt++) != '%') {
167 		if (c == '\0')
168 			return;
169 		putchar(c, flags, ttyp);
170 	}
171 again:
172 	c = *fmt++;
173 	/* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */
174 	switch (c) {
175 
176 	case 'l':
177 		goto again;
178 	case 'x': case 'X':
179 		b = 16;
180 		goto number;
181 	case 'd': case 'D':
182 		b = -10;
183 		goto number;
184 	case 'u':
185 		b = 10;
186 		goto number;
187 	case 'o': case 'O':
188 		b = 8;
189 number:
190 		printn((u_long)*adx, b, flags, ttyp);
191 		break;
192 	case 'c':
193 		b = *adx;
194 #if ENDIAN == LITTLE
195 		for (i = 24; i >= 0; i -= 8)
196 			if (c = (b >> i) & 0x7f)
197 				putchar(c, flags, ttyp);
198 #endif
199 #if ENDIAN == BIG
200 		if (c = (b & 0x7f))
201 			putchar(c, flags, ttyp);
202 #endif
203 		break;
204 	case 'b':
205 		b = *adx++;
206 		s = (char *)*adx;
207 		printn((u_long)b, *s++, flags, ttyp);
208 		any = 0;
209 		if (b) {
210 			while (i = *s++) {
211 				if (b & (1 << (i-1))) {
212 					putchar(any ? ',' : '<', flags, ttyp);
213 					any = 1;
214 					for (; (c = *s) > 32; s++)
215 						putchar(c, flags, ttyp);
216 				} else
217 					for (; *s > 32; s++)
218 						;
219 			}
220 			if (any)
221 				putchar('>', flags, ttyp);
222 		}
223 		break;
224 
225 	case 's':
226 		s = (char *)*adx;
227 		while (c = *s++)
228 			putchar(c, flags, ttyp);
229 		break;
230 
231 	case '%':
232 		putchar('%', flags, ttyp);
233 		break;
234 	}
235 	adx++;
236 	goto loop;
237 }
238 
239 /*
240  * Printn prints a number n in base b.
241  * We don't use recursion to avoid deep kernel stacks.
242  */
243 printn(n, b, flags, ttyp)
244 	u_long n;
245 	struct tty *ttyp;
246 {
247 	char prbuf[11];
248 	register char *cp;
249 
250 	if (b == -10) {
251 		if ((int)n < 0) {
252 			putchar('-', flags, ttyp);
253 			n = (unsigned)(-(int)n);
254 		}
255 		b = -b;
256 	}
257 	cp = prbuf;
258 	do {
259 		*cp++ = "0123456789abcdef"[n%b];
260 		n /= b;
261 	} while (n);
262 	do
263 		putchar(*--cp, flags, ttyp);
264 	while (cp > prbuf);
265 }
266 
267 /*
268  * Panic is called on unresolvable fatal errors.
269  * It prints "panic: mesg", and then reboots.
270  * If we are called twice, then we avoid trying to
271  * sync the disks as this often leads to recursive panics.
272  */
273 panic(s)
274 	char *s;
275 {
276 	int bootopt = RB_AUTOBOOT;
277 
278 	if (panicstr)
279 		bootopt |= RB_NOSYNC;
280 	else {
281 		panicstr = s;
282 	}
283 	printf("panic: %s\n", s);
284 	boot(RB_PANIC, bootopt);
285 }
286 
287 /*
288  * Warn that a system table is full.
289  */
290 tablefull(tab)
291 	char *tab;
292 {
293 
294 	log(LOG_ERR, "%s: table is full\n", tab);
295 }
296 
297 /*
298  * Hard error is the preface to plaintive error messages
299  * about failing disk transfers.
300  */
301 harderr(bp, cp)
302 	struct buf *bp;
303 	char *cp;
304 {
305 
306 	printf("%s%d%c: hard error sn%d ", cp,
307 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
308 }
309 
310 /*
311  * Print a character on console or users terminal.
312  * If destination is console then the last MSGBUFS characters
313  * are saved in msgbuf for inspection later.
314  */
315 /*ARGSUSED*/
316 putchar(c, flags, tp)
317 	register int c;
318 	struct tty *tp;
319 {
320 
321 	if (flags & TOTTY) {
322 		register s = spltty();
323 
324 		if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
325 		    (TS_CARR_ON | TS_ISOPEN)) {
326 			if (c == '\n')
327 				(void) ttyoutput('\r', tp);
328 			(void) ttyoutput(c, tp);
329 			ttstart(tp);
330 		}
331 		splx(s);
332 	}
333 	/*
334 	 * Can send to log only after memory management enabled:
335 	 * this has happened by the time maxmem is set.
336 	 */
337 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) {
338 		if (msgbuf.msg_magic != MSG_MAGIC) {
339 			register int i;
340 
341 			msgbuf.msg_magic = MSG_MAGIC;
342 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
343 			for (i=0; i < MSG_BSIZE; i++)
344 				msgbuf.msg_bufc[i] = 0;
345 		}
346 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
347 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
348 			msgbuf.msg_bufx = 0;
349 	}
350 	if ((flags & TOCONS) && c != '\0')
351 		cnputc(c);
352 }
353