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