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