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