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