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