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