subr_prf.c revision 1.40 1 /* $NetBSD: subr_prf.c,v 1.40 1997/04/17 00:06:28 thorpej 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 * XXX: This requires that stdarg.h defines: va_alist, va_dcl
64 */
65 #include <machine/stdarg.h>
66
67 #include "ipkdb.h"
68
69 #ifdef KADB
70 #include <machine/kdbparam.h>
71 #endif
72 #ifdef KGDB
73 #include <machine/cpu.h>
74 #endif
75
76 #define TOCONS 0x01
77 #define TOTTY 0x02
78 #define TOLOG 0x04
79
80 /*
81 * This is the size of the buffer that should be passed to ksnprintn().
82 * It's the length of a long in base 8, plus NULL.
83 */
84 #define KSNPRINTN_BUFSIZE (sizeof(long) * NBBY / 3 + 2)
85
86 struct tty *constty; /* pointer to console "window" tty */
87
88 void (*v_putc) __P((int)) = cnputc; /* routine to putc on virtual console */
89
90 static void putchar __P((int, int, struct tty *));
91 static char *ksnprintn __P((u_long, int, int *, char *, size_t));
92 void kprintf __P((const char *, int, struct tty *, va_list));
93
94 int consintr = 1; /* Ok to handle console interrupts? */
95
96 /*
97 * Variable panicstr contains argument to first call to panic; used as flag
98 * to indicate that the kernel has already called panic.
99 */
100 const char *panicstr;
101
102 /*
103 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
104 * and then reboots. If we are called twice, then we avoid trying to sync
105 * the disks as this often leads to recursive panics.
106 */
107 void
108 #ifdef __STDC__
109 panic(const char *fmt, ...)
110 #else
111 panic(fmt, va_alist)
112 char *fmt;
113 va_dcl
114 #endif
115 {
116 int bootopt;
117 va_list ap;
118
119 bootopt = RB_AUTOBOOT | RB_DUMP;
120 if (panicstr)
121 bootopt |= RB_NOSYNC;
122 else
123 panicstr = fmt;
124
125 va_start(ap, fmt);
126 #ifdef __powerpc__ /* XXX */
127 printf("panic: "); /* XXX */
128 vprintf(fmt, ap); /* XXX */
129 printf("\n"); /* XXX */
130 #else /* XXX */
131 printf("panic: %:\n", fmt, ap); /* XXX */
132 #endif /* XXX */
133 va_end(ap);
134
135 #if NIPKDB > 0
136 ipkdb_panic();
137 #endif
138 #ifdef KGDB
139 kgdb_panic();
140 #endif
141 #ifdef KADB
142 if (boothowto & RB_KDB)
143 kdbpanic();
144 #endif
145 #ifdef DDB
146 if (db_onpanic)
147 Debugger();
148 #endif
149 cpu_reboot(bootopt, NULL);
150 }
151
152 /*
153 * Warn that a system table is full.
154 */
155 void
156 tablefull(tab)
157 const char *tab;
158 {
159
160 log(LOG_ERR, "%s: table is full\n", tab);
161 }
162
163 /*
164 * Uprintf prints to the controlling terminal for the current process.
165 * It may block if the tty queue is overfull. No message is printed if
166 * the queue does not clear in a reasonable time.
167 */
168 void
169 #ifdef __STDC__
170 uprintf(const char *fmt, ...)
171 #else
172 uprintf(fmt, va_alist)
173 char *fmt;
174 va_dcl
175 #endif
176 {
177 register struct proc *p = curproc;
178 va_list ap;
179
180 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
181 va_start(ap, fmt);
182 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
183 va_end(ap);
184 }
185 }
186
187 tpr_t
188 tprintf_open(p)
189 register struct proc *p;
190 {
191
192 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
193 SESSHOLD(p->p_session);
194 return ((tpr_t) p->p_session);
195 }
196 return ((tpr_t) NULL);
197 }
198
199 void
200 tprintf_close(sess)
201 tpr_t sess;
202 {
203
204 if (sess)
205 SESSRELE((struct session *) sess);
206 }
207
208 /*
209 * tprintf prints on the controlling terminal associated
210 * with the given session.
211 */
212 void
213 #ifdef __STDC__
214 tprintf(tpr_t tpr, const char *fmt, ...)
215 #else
216 tprintf(tpr, fmt, va_alist)
217 tpr_t tpr;
218 char *fmt;
219 va_dcl
220 #endif
221 {
222 register struct session *sess = (struct session *)tpr;
223 struct tty *tp = NULL;
224 int flags = TOLOG;
225 va_list ap;
226
227 logpri(LOG_INFO);
228 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
229 flags |= TOTTY;
230 tp = sess->s_ttyp;
231 }
232 va_start(ap, fmt);
233 kprintf(fmt, flags, tp, ap);
234 va_end(ap);
235 logwakeup();
236 }
237
238 /*
239 * Ttyprintf displays a message on a tty; it should be used only by
240 * the tty driver, or anything that knows the underlying tty will not
241 * be revoke(2)'d away. Other callers should use tprintf.
242 */
243 void
244 #ifdef __STDC__
245 ttyprintf(struct tty *tp, const char *fmt, ...)
246 #else
247 ttyprintf(tp, fmt, va_alist)
248 struct tty *tp;
249 char *fmt;
250 va_dcl
251 #endif
252 {
253 va_list ap;
254
255 va_start(ap, fmt);
256 kprintf(fmt, TOTTY, tp, ap);
257 va_end(ap);
258 }
259
260 extern int log_open;
261
262 /*
263 * Log writes to the log buffer, and guarantees not to sleep (so can be
264 * called by interrupt routines). If there is no process reading the
265 * log yet, it writes to the console also.
266 */
267 void
268 #ifdef __STDC__
269 log(int level, const char *fmt, ...)
270 #else
271 log(level, fmt, va_alist)
272 int level;
273 char *fmt;
274 va_dcl
275 #endif
276 {
277 register int s;
278 va_list ap;
279
280 s = splhigh();
281 logpri(level);
282 va_start(ap, fmt);
283 kprintf(fmt, TOLOG, NULL, ap);
284 splx(s);
285 va_end(ap);
286 if (!log_open) {
287 va_start(ap, fmt);
288 kprintf(fmt, TOCONS, NULL, ap);
289 va_end(ap);
290 }
291 logwakeup();
292 }
293
294 void
295 logpri(level)
296 int level;
297 {
298 register int ch;
299 register char *p;
300 char snbuf[KSNPRINTN_BUFSIZE];
301
302 putchar('<', TOLOG, NULL);
303 for (p = ksnprintn((u_long)level, 10, NULL, snbuf, sizeof(snbuf));
304 (ch = *p--) != 0;)
305 putchar(ch, TOLOG, NULL);
306 putchar('>', TOLOG, NULL);
307 }
308
309 void
310 #ifdef __STDC__
311 addlog(const char *fmt, ...)
312 #else
313 addlog(fmt, va_alist)
314 char *fmt;
315 va_dcl
316 #endif
317 {
318 register int s;
319 va_list ap;
320
321 s = splhigh();
322 va_start(ap, fmt);
323 kprintf(fmt, TOLOG, NULL, ap);
324 splx(s);
325 va_end(ap);
326 if (!log_open) {
327 va_start(ap, fmt);
328 kprintf(fmt, TOCONS, NULL, ap);
329 va_end(ap);
330 }
331 logwakeup();
332 }
333
334 void
335 #ifdef __STDC__
336 printf(const char *fmt, ...)
337 #else
338 printf(fmt, va_alist)
339 char *fmt;
340 va_dcl
341 #endif
342 {
343 va_list ap;
344 register int savintr;
345
346 savintr = consintr; /* disable interrupts */
347 consintr = 0;
348 va_start(ap, fmt);
349 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
350 va_end(ap);
351 if (!panicstr)
352 logwakeup();
353 consintr = savintr; /* reenable interrupts */
354 }
355
356 #ifdef __powerpc__ /* XXX XXX XXX */
357 void
358 vprintf(fmt, ap)
359 const char *fmt;
360 va_list ap;
361 {
362 register int savintr;
363
364 savintr = consintr; /* disable interrupts */
365 consintr = 0;
366 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
367 if (!panicstr)
368 logwakeup();
369 consintr = savintr; /* reenable interrupts */
370 }
371 #endif /* __powerpc__ */ /* XXX XXX XXX */
372
373 /*
374 * Scaled down version of printf(3).
375 *
376 * Two additional formats:
377 *
378 * The format %b is supported to decode error registers.
379 * Its usage is:
380 *
381 * printf("reg=%b\n", regval, "<base><arg>*");
382 *
383 * where <base> is the output base expressed as a control character, e.g.
384 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
385 * the first of which gives the bit number to be inspected (origin 1), and
386 * the next characters (up to a control character, i.e. a character <= 32),
387 * give the name of the register. Thus:
388 *
389 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
390 *
391 * would produce output:
392 *
393 * reg=3<BITTWO,BITONE>
394 *
395 * The format %: passes an additional format string and argument list
396 * recursively. Its usage is:
397 *
398 * fn(char *fmt, ...)
399 * {
400 * va_list ap;
401 * va_start(ap, fmt);
402 * printf("prefix: %: suffix\n", fmt, ap);
403 * va_end(ap);
404 * }
405 *
406 * Space or zero padding and a field width are supported for the numeric
407 * formats only.
408 */
409 void
410 kprintf(fmt, flags, tp, ap)
411 register const char *fmt;
412 int flags;
413 struct tty *tp;
414 va_list ap;
415 {
416 register char *p, *q;
417 register int ch, n;
418 u_long ul;
419 int base, lflag, tmp, width;
420 char padc, snbuf[KSNPRINTN_BUFSIZE];
421
422 for (;;) {
423 padc = ' ';
424 width = 0;
425 while ((ch = *(const u_char *)fmt++) != '%') {
426 if (ch == '\0')
427 return;
428 putchar(ch, flags, tp);
429 }
430 lflag = 0;
431 reswitch: switch (ch = *(const u_char *)fmt++) {
432 case '0':
433 case '.':
434 padc = '0';
435 goto reswitch;
436 case '1': case '2': case '3': case '4':
437 case '5': case '6': case '7': case '8': case '9':
438 for (width = 0;; ++fmt) {
439 width = width * 10 + ch - '0';
440 ch = *fmt;
441 if (ch < '0' || ch > '9')
442 break;
443 }
444 goto reswitch;
445 case 'l':
446 lflag = 1;
447 goto reswitch;
448 case 'b':
449 ul = va_arg(ap, int);
450 p = va_arg(ap, char *);
451 for (q = ksnprintn(ul, *p++, NULL, snbuf,
452 sizeof(snbuf)); (ch = *q--) != 0;)
453 putchar(ch, flags, tp);
454
455 if (!ul)
456 break;
457
458 for (tmp = 0; (n = *p++) != 0;) {
459 if (ul & (1 << (n - 1))) {
460 putchar(tmp ? ',' : '<', flags, tp);
461 for (; (n = *p) > ' '; ++p)
462 putchar(n, flags, tp);
463 tmp = 1;
464 } else
465 for (; *p > ' '; ++p)
466 continue;
467 }
468 if (tmp)
469 putchar('>', flags, tp);
470 break;
471 case 'c':
472 putchar(va_arg(ap, int), flags, tp);
473 break;
474 #ifndef __powerpc__ /* XXX XXX XXX */
475 case ':':
476 p = va_arg(ap, char *);
477 kprintf(p, flags, tp, va_arg(ap, va_list));
478 break;
479 #endif /* __powerpc__ */ /* XXX XXX XXX */
480 case 's':
481 if ((p = va_arg(ap, char *)) == NULL)
482 p = "(null)";
483 while ((ch = *p++) != 0)
484 putchar(ch, flags, tp);
485 break;
486 case 'd':
487 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
488 if ((long)ul < 0) {
489 putchar('-', flags, tp);
490 ul = -(long)ul;
491 }
492 base = 10;
493 goto number;
494 case 'o':
495 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
496 base = 8;
497 goto number;
498 case 'u':
499 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
500 base = 10;
501 goto number;
502 case 'p':
503 putchar('0', flags, tp);
504 putchar('x', flags, tp);
505 ul = (u_long)va_arg(ap, void *);
506 base = 16;
507 goto number;
508 case 'x':
509 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
510 base = 16;
511 number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
512 if (width && (width -= tmp) > 0)
513 while (width--)
514 putchar(padc, flags, tp);
515 while ((ch = *p--) != 0)
516 putchar(ch, flags, tp);
517 break;
518 default:
519 putchar('%', flags, tp);
520 if (lflag)
521 putchar('l', flags, tp);
522 /* FALLTHROUGH */
523 case '%':
524 putchar(ch, flags, tp);
525 }
526 }
527 }
528
529 /*
530 * Print a character on console or users terminal. If destination is
531 * the console then the last MSGBUFS characters are saved in msgbuf for
532 * inspection later.
533 */
534 static void
535 putchar(c, flags, tp)
536 register int c;
537 int flags;
538 struct tty *tp;
539 {
540 extern int msgbufmapped;
541 register struct msgbuf *mbp;
542
543 if (panicstr)
544 constty = NULL;
545 if ((flags & TOCONS) && tp == NULL && constty) {
546 tp = constty;
547 flags |= TOTTY;
548 }
549 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
550 (flags & TOCONS) && tp == constty)
551 constty = NULL;
552 if ((flags & TOLOG) &&
553 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
554 mbp = msgbufp;
555 if (mbp->msg_magic != MSG_MAGIC) {
556 bzero((caddr_t)mbp, sizeof(*mbp));
557 mbp->msg_magic = MSG_MAGIC;
558 }
559 mbp->msg_bufc[mbp->msg_bufx++] = c;
560 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
561 mbp->msg_bufx = 0;
562 }
563 if ((flags & TOCONS) && constty == NULL && c != '\0')
564 (*v_putc)(c);
565 }
566
567 /*
568 * Scaled down version of sprintf(3).
569 */
570 int
571 #ifdef __STDC__
572 sprintf(char *buf, const char *cfmt, ...)
573 #else
574 sprintf(buf, cfmt, va_alist)
575 char *buf;
576 const char *cfmt;
577 va_dcl
578 #endif
579 {
580 register const char *fmt = cfmt;
581 register char *p, *bp;
582 register int ch, base;
583 u_long ul;
584 int lflag, tmp, width;
585 va_list ap;
586 char padc, snbuf[KSNPRINTN_BUFSIZE];
587
588 va_start(ap, cfmt);
589 for (bp = buf; ; ) {
590 padc = ' ';
591 width = 0;
592 while ((ch = *(const u_char *)fmt++) != '%')
593 if ((*bp++ = ch) == '\0')
594 return ((bp - buf) - 1);
595
596 lflag = 0;
597 reswitch: switch (ch = *(const u_char *)fmt++) {
598 case '0':
599 padc = '0';
600 goto reswitch;
601 case '1': case '2': case '3': case '4':
602 case '5': case '6': case '7': case '8': case '9':
603 for (width = 0;; ++fmt) {
604 width = width * 10 + ch - '0';
605 ch = *fmt;
606 if (ch < '0' || ch > '9')
607 break;
608 }
609 goto reswitch;
610 case 'l':
611 lflag = 1;
612 goto reswitch;
613 /* case 'b': ... break; XXX */
614 case 'c':
615 *bp++ = va_arg(ap, int);
616 break;
617 /* case 'r': ... break; XXX */
618 case 's':
619 p = va_arg(ap, char *);
620 while ((*bp++ = *p++) != 0)
621 continue;
622 --bp;
623 break;
624 case 'd':
625 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
626 if ((long)ul < 0) {
627 *bp++ = '-';
628 ul = -(long)ul;
629 }
630 base = 10;
631 goto number;
632 break;
633 case 'o':
634 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
635 base = 8;
636 goto number;
637 break;
638 case 'u':
639 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
640 base = 10;
641 goto number;
642 break;
643 case 'p':
644 *bp++ = '0';
645 *bp++ = 'x';
646 ul = (u_long)va_arg(ap, void *);
647 base = 16;
648 goto number;
649 case 'x':
650 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
651 base = 16;
652 number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
653 if (width && (width -= tmp) > 0)
654 while (width--)
655 *bp++ = padc;
656 while ((ch = *p--) != 0)
657 *bp++ = ch;
658 break;
659 default:
660 *bp++ = '%';
661 if (lflag)
662 *bp++ = 'l';
663 /* FALLTHROUGH */
664 case '%':
665 *bp++ = ch;
666 }
667 }
668 va_end(ap);
669 }
670
671 /*
672 * Put a number (base <= 16) in a buffer in reverse order; return an
673 * optional length and a pointer to the NULL terminated (preceded?)
674 * buffer.
675 */
676 static char *
677 ksnprintn(ul, base, lenp, buf, buflen)
678 register u_long ul;
679 register int base, *lenp;
680 char *buf;
681 size_t buflen;
682 {
683 register char *p;
684
685 p = buf;
686 *p = '\0'; /* ensure NULL `termination' */
687
688 /*
689 * Don't even bother of the buffer's not big enough. No
690 * value at all is better than a wrong value, and we
691 * have a lot of control over the buffer that's passed
692 * to this function, since it's not exported.
693 */
694 if (buflen < KSNPRINTN_BUFSIZE)
695 return (p);
696
697 do {
698 *++p = "0123456789abcdef"[ul % base];
699 } while (ul /= base);
700 if (lenp)
701 *lenp = p - buf;
702 return (p);
703 }
704
705 /*
706 * Print a bitmask into the provided buffer, and return a pointer
707 * to that buffer.
708 */
709 char *
710 bitmask_snprintf(ul, p, buf, buflen)
711 u_long ul;
712 const char *p;
713 char *buf;
714 size_t buflen;
715 {
716 char *bp, *q;
717 size_t left;
718 register int n;
719 int ch, tmp;
720 char snbuf[KSNPRINTN_BUFSIZE];
721
722 bp = buf;
723 bzero(buf, buflen);
724
725 /*
726 * Always leave room for the trailing NULL.
727 */
728 left = buflen - 1;
729
730 /*
731 * Print the value into the buffer. Abort if there's not
732 * enough room.
733 */
734 if (buflen < KSNPRINTN_BUFSIZE)
735 return (buf);
736
737 for (q = ksnprintn(ul, *p++, NULL, snbuf, sizeof(snbuf));
738 (ch = *q--) != 0;) {
739 *bp++ = ch;
740 left--;
741 }
742
743 /*
744 * If the value we printed was 0, or if we don't have room for
745 * "<x>", we're done.
746 */
747 if (ul == 0 || left < 3)
748 return (buf);
749
750 #define PUTBYTE(b, c, l) \
751 *(b)++ = (c); \
752 if (--(l) == 0) \
753 goto out;
754
755 for (tmp = 0; (n = *p++) != 0;) {
756 if (ul & (1 << (n - 1))) {
757 PUTBYTE(bp, tmp ? ',' : '<', left);
758 for (; (n = *p) > ' '; ++p) {
759 PUTBYTE(bp, n, left);
760 }
761 tmp = 1;
762 } else
763 for (; *p > ' '; ++p)
764 continue;
765 }
766 if (tmp)
767 *bp = '>';
768
769 #undef PUTBYTE
770
771 out:
772 return (buf);
773 }
774