1 /*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * %sccs.include.redist.c%
11 *
12 * @(#)subr_prf.c 8.4 (Berkeley) 05/04/95
13 */
14
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/buf.h>
18 #include <sys/conf.h>
19 #include <sys/reboot.h>
20 #include <sys/msgbuf.h>
21 #include <sys/proc.h>
22 #include <sys/ioctl.h>
23 #include <sys/vnode.h>
24 #include <sys/file.h>
25 #include <sys/tty.h>
26 #include <sys/tprintf.h>
27 #include <sys/syslog.h>
28 #include <sys/malloc.h>
29
30 /*
31 * Note that stdarg.h and the ANSI style va_start macro is used for both
32 * ANSI and traditional C compilers.
33 */
34 #include <machine/stdarg.h>
35
36 #ifdef KADB
37 #include <machine/kdbparam.h>
38 #endif
39
40 #define TOCONS 0x01
41 #define TOTTY 0x02
42 #define TOLOG 0x04
43
44 struct tty *constty; /* pointer to console "window" tty */
45
46 extern cnputc(); /* standard console putc */
47 int (*v_putc)() = cnputc; /* routine to putc on virtual console */
48
49 void logpri __P((int level));
50 static void putchar __P((int ch, int flags, struct tty *tp));
51 static char *ksprintn __P((u_long num, int base, int *len));
52 void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
53
54 int consintr = 1; /* Ok to handle console interrupts? */
55
56 /*
57 * Variable panicstr contains argument to first call to panic; used as flag
58 * to indicate that the kernel has already called panic.
59 */
60 const char *panicstr;
61
62 /*
63 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
64 * and then reboots. If we are called twice, then we avoid trying to sync
65 * the disks as this often leads to recursive panics.
66 */
67 #ifdef __GNUC__
68 volatile void boot(int flags); /* boot() does not return */
69 volatile /* panic() does not return */
70 #endif
71 void
72 #ifdef __STDC__
panic(const char * fmt,...)73 panic(const char *fmt, ...)
74 #else
75 panic(fmt, va_alist)
76 char *fmt;
77 #endif
78 {
79 int bootopt;
80 va_list ap;
81
82 bootopt = RB_AUTOBOOT | RB_DUMP;
83 if (panicstr)
84 bootopt |= RB_NOSYNC;
85 else
86 panicstr = fmt;
87
88 va_start(ap, fmt);
89 printf("panic: %r\n", fmt, ap);
90 va_end(ap);
91
92 #ifdef KGDB
93 kgdb_panic();
94 #endif
95 #ifdef KADB
96 if (boothowto & RB_KDB)
97 kdbpanic();
98 #endif
99 boot(bootopt);
100 }
101
102 /*
103 * Warn that a system table is full.
104 */
105 void
tablefull(tab)106 tablefull(tab)
107 const char *tab;
108 {
109
110 log(LOG_ERR, "%s: table is full\n", tab);
111 }
112
113 /*
114 * Uprintf prints to the controlling terminal for the current process.
115 * It may block if the tty queue is overfull. No message is printed if
116 * the queue does not clear in a reasonable time.
117 */
118 void
119 #ifdef __STDC__
uprintf(const char * fmt,...)120 uprintf(const char *fmt, ...)
121 #else
122 uprintf(fmt, va_alist)
123 char *fmt;
124 #endif
125 {
126 register struct proc *p = curproc;
127 va_list ap;
128
129 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
130 va_start(ap, fmt);
131 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
132 va_end(ap);
133 }
134 }
135
136 tpr_t
tprintf_open(p)137 tprintf_open(p)
138 register struct proc *p;
139 {
140
141 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
142 SESSHOLD(p->p_session);
143 return ((tpr_t) p->p_session);
144 }
145 return ((tpr_t) NULL);
146 }
147
148 void
tprintf_close(sess)149 tprintf_close(sess)
150 tpr_t sess;
151 {
152
153 if (sess)
154 SESSRELE((struct session *) sess);
155 }
156
157 /*
158 * tprintf prints on the controlling terminal associated
159 * with the given session.
160 */
161 void
162 #ifdef __STDC__
tprintf(tpr_t tpr,const char * fmt,...)163 tprintf(tpr_t tpr, const char *fmt, ...)
164 #else
165 tprintf(tpr, fmt, va_alist)
166 tpr_t tpr;
167 char *fmt;
168 #endif
169 {
170 register struct session *sess = (struct session *)tpr;
171 struct tty *tp = NULL;
172 int flags = TOLOG;
173 va_list ap;
174
175 logpri(LOG_INFO);
176 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
177 flags |= TOTTY;
178 tp = sess->s_ttyp;
179 }
180 va_start(ap, fmt);
181 kprintf(fmt, flags, tp, ap);
182 va_end(ap);
183 logwakeup();
184 }
185
186 /*
187 * Ttyprintf displays a message on a tty; it should be used only by
188 * the tty driver, or anything that knows the underlying tty will not
189 * be revoke(2)'d away. Other callers should use tprintf.
190 */
191 void
192 #ifdef __STDC__
ttyprintf(struct tty * tp,const char * fmt,...)193 ttyprintf(struct tty *tp, const char *fmt, ...)
194 #else
195 ttyprintf(tp, fmt, va_alist)
196 struct tty *tp;
197 char *fmt;
198 #endif
199 {
200 va_list ap;
201
202 va_start(ap, fmt);
203 kprintf(fmt, TOTTY, tp, ap);
204 va_end(ap);
205 }
206
207 extern int log_open;
208
209 /*
210 * Log writes to the log buffer, and guarantees not to sleep (so can be
211 * called by interrupt routines). If there is no process reading the
212 * log yet, it writes to the console also.
213 */
214 void
215 #ifdef __STDC__
log(int level,const char * fmt,...)216 log(int level, const char *fmt, ...)
217 #else
218 log(level, fmt, va_alist)
219 int level;
220 char *fmt;
221 #endif
222 {
223 register int s;
224 va_list ap;
225
226 s = splhigh();
227 logpri(level);
228 va_start(ap, fmt);
229 kprintf(fmt, TOLOG, NULL, ap);
230 splx(s);
231 va_end(ap);
232 if (!log_open) {
233 va_start(ap, fmt);
234 kprintf(fmt, TOCONS, NULL, ap);
235 va_end(ap);
236 }
237 logwakeup();
238 }
239
240 void
logpri(level)241 logpri(level)
242 int level;
243 {
244 register int ch;
245 register char *p;
246
247 putchar('<', TOLOG, NULL);
248 for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
249 putchar(ch, TOLOG, NULL);
250 putchar('>', TOLOG, NULL);
251 }
252
253 void
254 #ifdef __STDC__
addlog(const char * fmt,...)255 addlog(const char *fmt, ...)
256 #else
257 addlog(fmt, va_alist)
258 char *fmt;
259 #endif
260 {
261 register int s;
262 va_list ap;
263
264 s = splhigh();
265 va_start(ap, fmt);
266 kprintf(fmt, TOLOG, NULL, ap);
267 splx(s);
268 va_end(ap);
269 if (!log_open) {
270 va_start(ap, fmt);
271 kprintf(fmt, TOCONS, NULL, ap);
272 va_end(ap);
273 }
274 logwakeup();
275 }
276
277 void
278 #ifdef __STDC__
printf(const char * fmt,...)279 printf(const char *fmt, ...)
280 #else
281 printf(fmt, va_alist)
282 char *fmt;
283 #endif
284 {
285 va_list ap;
286 register int savintr;
287
288 savintr = consintr; /* disable interrupts */
289 consintr = 0;
290 va_start(ap, fmt);
291 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
292 va_end(ap);
293 if (!panicstr)
294 logwakeup();
295 consintr = savintr; /* reenable interrupts */
296 }
297
298 /*
299 * Scaled down version of printf(3).
300 *
301 * Two additional formats:
302 *
303 * The format %b is supported to decode error registers.
304 * Its usage is:
305 *
306 * printf("reg=%b\n", regval, "<base><arg>*");
307 *
308 * where <base> is the output base expressed as a control character, e.g.
309 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
310 * the first of which gives the bit number to be inspected (origin 1), and
311 * the next characters (up to a control character, i.e. a character <= 32),
312 * give the name of the register. Thus:
313 *
314 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
315 *
316 * would produce output:
317 *
318 * reg=3<BITTWO,BITONE>
319 *
320 * The format %r passes an additional format string and argument list
321 * recursively. Its usage is:
322 *
323 * fn(char *fmt, ...)
324 * {
325 * va_list ap;
326 * va_start(ap, fmt);
327 * printf("prefix: %r: suffix\n", fmt, ap);
328 * va_end(ap);
329 * }
330 *
331 * Space or zero padding and a field width are supported for the numeric
332 * formats only.
333 */
334 void
kprintf(fmt,flags,tp,ap)335 kprintf(fmt, flags, tp, ap)
336 register const char *fmt;
337 int flags;
338 struct tty *tp;
339 va_list ap;
340 {
341 register char *p, *q;
342 register int ch, n;
343 u_long ul;
344 int base, lflag, tmp, width;
345 char padc;
346
347 for (;;) {
348 padc = ' ';
349 width = 0;
350 while ((ch = *(u_char *)fmt++) != '%') {
351 if (ch == '\0')
352 return;
353 putchar(ch, flags, tp);
354 }
355 lflag = 0;
356 reswitch: switch (ch = *(u_char *)fmt++) {
357 case '0':
358 padc = '0';
359 goto reswitch;
360 case '1': case '2': case '3': case '4':
361 case '5': case '6': case '7': case '8': case '9':
362 for (width = 0;; ++fmt) {
363 width = width * 10 + ch - '0';
364 ch = *fmt;
365 if (ch < '0' || ch > '9')
366 break;
367 }
368 goto reswitch;
369 case 'l':
370 lflag = 1;
371 goto reswitch;
372 case 'b':
373 ul = va_arg(ap, int);
374 p = va_arg(ap, char *);
375 for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
376 putchar(ch, flags, tp);
377
378 if (!ul)
379 break;
380
381 for (tmp = 0; n = *p++;) {
382 if (ul & (1 << (n - 1))) {
383 putchar(tmp ? ',' : '<', flags, tp);
384 for (; (n = *p) > ' '; ++p)
385 putchar(n, flags, tp);
386 tmp = 1;
387 } else
388 for (; *p > ' '; ++p)
389 continue;
390 }
391 if (tmp)
392 putchar('>', flags, tp);
393 break;
394 case 'c':
395 putchar(va_arg(ap, int), flags, tp);
396 break;
397 case 'r':
398 p = va_arg(ap, char *);
399 kprintf(p, flags, tp, va_arg(ap, va_list));
400 break;
401 case 's':
402 p = va_arg(ap, char *);
403 while (ch = *p++)
404 putchar(ch, flags, tp);
405 break;
406 case 'd':
407 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
408 if ((long)ul < 0) {
409 putchar('-', flags, tp);
410 ul = -(long)ul;
411 }
412 base = 10;
413 goto number;
414 case 'o':
415 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
416 base = 8;
417 goto number;
418 case 'u':
419 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
420 base = 10;
421 goto number;
422 case 'x':
423 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
424 base = 16;
425 number: p = ksprintn(ul, base, &tmp);
426 if (width && (width -= tmp) > 0)
427 while (width--)
428 putchar(padc, flags, tp);
429 while (ch = *p--)
430 putchar(ch, flags, tp);
431 break;
432 default:
433 putchar('%', flags, tp);
434 if (lflag)
435 putchar('l', flags, tp);
436 /* FALLTHROUGH */
437 case '%':
438 putchar(ch, flags, tp);
439 }
440 }
441 }
442
443 /*
444 * Print a character on console or users terminal. If destination is
445 * the console then the last MSGBUFS characters are saved in msgbuf for
446 * inspection later.
447 */
448 static void
putchar(c,flags,tp)449 putchar(c, flags, tp)
450 register int c;
451 int flags;
452 struct tty *tp;
453 {
454 extern int msgbufmapped;
455 register struct msgbuf *mbp;
456
457 if (panicstr)
458 constty = NULL;
459 if ((flags & TOCONS) && tp == NULL && constty) {
460 tp = constty;
461 flags |= TOTTY;
462 }
463 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
464 (flags & TOCONS) && tp == constty)
465 constty = NULL;
466 if ((flags & TOLOG) &&
467 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
468 mbp = msgbufp;
469 if (mbp->msg_magic != MSG_MAGIC) {
470 bzero((caddr_t)mbp, sizeof(*mbp));
471 mbp->msg_magic = MSG_MAGIC;
472 }
473 mbp->msg_bufc[mbp->msg_bufx++] = c;
474 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
475 mbp->msg_bufx = 0;
476 /* If the buffer is full, keep the most recent data. */
477 if (mbp->msg_bufr == mbp->msg_bufx) {
478 if (++mbp->msg_bufr >= MSG_BSIZE)
479 mbp->msg_bufr = 0;
480 }
481 }
482 if ((flags & TOCONS) && constty == NULL && c != '\0')
483 (*v_putc)(c);
484 }
485
486 /*
487 * Scaled down version of sprintf(3).
488 */
489 #ifdef __STDC__
sprintf(char * buf,const char * cfmt,...)490 sprintf(char *buf, const char *cfmt, ...)
491 #else
492 sprintf(buf, cfmt, va_alist)
493 char *buf, *cfmt;
494 #endif
495 {
496 register const char *fmt = cfmt;
497 register char *p, *bp;
498 register int ch, base;
499 u_long ul;
500 int lflag;
501 va_list ap;
502
503 va_start(ap, cfmt);
504 for (bp = buf; ; ) {
505 while ((ch = *(u_char *)fmt++) != '%')
506 if ((*bp++ = ch) == '\0')
507 return ((bp - buf) - 1);
508
509 lflag = 0;
510 reswitch: switch (ch = *(u_char *)fmt++) {
511 case 'l':
512 lflag = 1;
513 goto reswitch;
514 case 'c':
515 *bp++ = va_arg(ap, int);
516 break;
517 case 's':
518 p = va_arg(ap, char *);
519 while (*bp++ = *p++)
520 continue;
521 --bp;
522 break;
523 case 'd':
524 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
525 if ((long)ul < 0) {
526 *bp++ = '-';
527 ul = -(long)ul;
528 }
529 base = 10;
530 goto number;
531 break;
532 case 'o':
533 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
534 base = 8;
535 goto number;
536 break;
537 case 'u':
538 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
539 base = 10;
540 goto number;
541 break;
542 case 'x':
543 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
544 base = 16;
545 number: for (p = ksprintn(ul, base, NULL); ch = *p--;)
546 *bp++ = ch;
547 break;
548 default:
549 *bp++ = '%';
550 if (lflag)
551 *bp++ = 'l';
552 /* FALLTHROUGH */
553 case '%':
554 *bp++ = ch;
555 }
556 }
557 va_end(ap);
558 }
559
560 /*
561 * Put a number (base <= 16) in a buffer in reverse order; return an
562 * optional length and a pointer to the NULL terminated (preceded?)
563 * buffer.
564 */
565 static char *
ksprintn(ul,base,lenp)566 ksprintn(ul, base, lenp)
567 register u_long ul;
568 register int base, *lenp;
569 { /* A long in base 8, plus NULL. */
570 static char buf[sizeof(long) * NBBY / 3 + 2];
571 register char *p;
572
573 p = buf;
574 do {
575 *++p = "0123456789abcdef"[ul % base];
576 } while (ul /= base);
577 if (lenp)
578 *lenp = p - buf;
579 return (p);
580 }
581