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