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