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