xref: /csrg-svn/sys/kern/subr_prf.c (revision 24839)
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.9 (Berkeley) 09/17/85
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  * and does no watermark checking - (so no verbose messages).
70  */
71 /*VARARGS1*/
72 uprintf(fmt, x1)
73 	char *fmt;
74 	unsigned x1;
75 {
76 
77 	prf(fmt, &x1, TOTTY, u.u_ttyp);
78 }
79 
80 /*
81  * tprintf prints on the specified terminal (console if none)
82  * and logs the message.  It is designed for error messages from
83  * single-open devices, and may be called from interrupt level.
84  */
85 /*VARARGS2*/
86 tprintf(ttyp, fmt, x1)
87 	struct tty *ttyp;
88 	char *fmt;
89 	unsigned x1;
90 {
91 
92 	prf(fmt, &x1, TOTTY | TOLOG, ttyp);
93 }
94 
95 /*
96  * Log writes to the log buffer,
97  * and guarantees not to sleep (so can be called by interrupt routines).
98  * If there is no process reading the log yet, it writes to the console also.
99  */
100 /*VARARGS2*/
101 log(level, fmt, x1)
102 	char *fmt;
103 	unsigned x1;
104 {
105 	register s = splhigh();
106 	extern int log_open;
107 
108 	putchar('<', TOLOG, (struct tty *)0);
109 	printn(level, 10, TOLOG, (struct tty *)0);
110 	putchar('>', TOLOG, (struct tty *)0);
111 	prf(fmt, &x1, TOLOG, (struct tty *)0);
112 	splx(s);
113 	if (!log_open)
114 		prf(fmt, &x1, TOCONS, (struct tty *)0);
115 	logwakeup();
116 }
117 
118 prf(fmt, adx, flags, ttyp)
119 	register char *fmt;
120 	register u_int *adx;
121 	struct tty *ttyp;
122 {
123 	register int b, c, i;
124 	char *s;
125 	int any;
126 
127 loop:
128 	while ((c = *fmt++) != '%') {
129 		if (c == '\0')
130 			return;
131 		putchar(c, flags, ttyp);
132 	}
133 again:
134 	c = *fmt++;
135 	/* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */
136 	switch (c) {
137 
138 	case 'l':
139 		goto again;
140 	case 'x': case 'X':
141 		b = 16;
142 		goto number;
143 	case 'd': case 'D':
144 	case 'u':		/* what a joke */
145 		b = 10;
146 		goto number;
147 	case 'o': case 'O':
148 		b = 8;
149 number:
150 		printn((u_long)*adx, b, flags, ttyp);
151 		break;
152 	case 'c':
153 		b = *adx;
154 		for (i = 24; i >= 0; i -= 8)
155 			if (c = (b >> i) & 0x7f)
156 				putchar(c, flags, ttyp);
157 		break;
158 	case 'b':
159 		b = *adx++;
160 		s = (char *)*adx;
161 		printn((u_long)b, *s++, flags, ttyp);
162 		any = 0;
163 		if (b) {
164 			while (i = *s++) {
165 				if (b & (1 << (i-1))) {
166 					putchar(any? ',' : '<', flags, ttyp);
167 					any = 1;
168 					for (; (c = *s) > 32; s++)
169 						putchar(c, flags, ttyp);
170 				} else
171 					for (; *s > 32; s++)
172 						;
173 			}
174 			if (any)
175 				putchar('>', flags, ttyp);
176 		}
177 		break;
178 
179 	case 's':
180 		s = (char *)*adx;
181 		while (c = *s++)
182 			putchar(c, flags, ttyp);
183 		break;
184 
185 	case '%':
186 		putchar('%', flags, ttyp);
187 		break;
188 	}
189 	adx++;
190 	goto loop;
191 }
192 
193 /*
194  * Printn prints a number n in base b.
195  * We don't use recursion to avoid deep kernel stacks.
196  */
197 printn(n, b, flags, ttyp)
198 	u_long n;
199 	struct tty *ttyp;
200 {
201 	char prbuf[11];
202 	register char *cp;
203 
204 	if (b == 10 && (int)n < 0) {
205 		putchar('-', flags, ttyp);
206 		n = (unsigned)(-(int)n);
207 	}
208 	cp = prbuf;
209 	do {
210 		*cp++ = "0123456789abcdef"[n%b];
211 		n /= b;
212 	} while (n);
213 	do
214 		putchar(*--cp, flags, ttyp);
215 	while (cp > prbuf);
216 }
217 
218 /*
219  * Panic is called on unresolvable fatal errors.
220  * It prints "panic: mesg", and then reboots.
221  * If we are called twice, then we avoid trying to
222  * sync the disks as this often leads to recursive panics.
223  */
224 panic(s)
225 	char *s;
226 {
227 	int bootopt = RB_AUTOBOOT;
228 
229 	if (panicstr)
230 		bootopt |= RB_NOSYNC;
231 	else {
232 		panicstr = s;
233 	}
234 	printf("panic: %s\n", s);
235 	boot(RB_PANIC, bootopt);
236 }
237 
238 /*
239  * Warn that a system table is full.
240  */
241 tablefull(tab)
242 	char *tab;
243 {
244 
245 	log(LOG_ERR, "%s: table is full\n", tab);
246 }
247 
248 /*
249  * Hard error is the preface to plaintive error messages
250  * about failing disk transfers.
251  */
252 harderr(bp, cp)
253 	struct buf *bp;
254 	char *cp;
255 {
256 
257 	printf("%s%d%c: hard error sn%d ", cp,
258 	    minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
259 }
260 
261 /*
262  * Print a character on console or users terminal.
263  * If destination is console then the last MSGBUFS characters
264  * are saved in msgbuf for inspection later.
265  */
266 /*ARGSUSED*/
267 putchar(c, flags, tp)
268 	register int c;
269 	struct tty *tp;
270 {
271 	extern struct tty cons;
272 
273 	if (flags & TOTTY) {
274 		if (tp == (struct tty *)NULL && (flags & TOCONS) == 0)
275 			tp = &cons;
276 		if (tp && (tp->t_state & TS_CARR_ON)) {
277 			register s = spl6();
278 			if (c == '\n')
279 				(void) ttyoutput('\r', tp);
280 			(void) ttyoutput(c, tp);
281 			ttstart(tp);
282 			splx(s);
283 		}
284 	}
285 	if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177
286 #ifdef vax
287 	    && mfpr(MAPEN)
288 #endif
289 	    ) {
290 		if (msgbuf.msg_magic != MSG_MAGIC) {
291 			register int i;
292 
293 			msgbuf.msg_magic = MSG_MAGIC;
294 			msgbuf.msg_bufx = msgbuf.msg_bufr = 0;
295 			for (i=0; i < MSG_BSIZE; i++)
296 				msgbuf.msg_bufc[i] = 0;
297 		}
298 		if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE)
299 			msgbuf.msg_bufx = 0;
300 		msgbuf.msg_bufc[msgbuf.msg_bufx++] = c;
301 	}
302 	if ((flags & TOCONS) && c != '\0')
303 		cnputc(c);
304 }
305