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