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