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