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