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