This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / kern / subr_prf.c
CommitLineData
169d8a33
RG
1/*
2 * Copyright (c) UNIX System Laboratories, Inc. All or some portions
3 * of this file are derived from material licensed to the
4 * University of California by American Telephone and Telegraph Co.
5 * or UNIX System Laboratories, Inc. and are reproduced herein with
6 * the permission of UNIX System Laboratories, Inc.
7 */
15637ed4
RG
8/*-
9 * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
10 * All rights reserved.
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 *
600f7f07 40 * from: @(#)subr_prf.c 7.30 (Berkeley) 6/29/91
169d8a33 41 * $Id: subr_prf.c,v 1.7 1994/02/27 15:07:20 phk Exp $
15637ed4
RG
42 */
43
44#include "param.h"
45#include "systm.h"
46#include "buf.h"
47#include "conf.h"
48#include "reboot.h"
49#include "msgbuf.h"
50#include "proc.h"
51#include "ioctl.h"
52#include "vnode.h"
53#include "file.h"
54#include "tty.h"
55#include "tprintf.h"
56#include "syslog.h"
57#include "malloc.h"
58
59/*
60 * Note that stdarg.h and the ANSI style va_start macro is used for both
61 * ANSI and traditional C compilers.
62 */
63#include <machine/stdarg.h>
64
65#ifdef KADB
66#include "machine/kdbparam.h"
67#endif
68
69#define TOCONS 0x01
70#define TOTTY 0x02
71#define TOLOG 0x04
72
73struct tty *constty; /* pointer to console "window" tty */
74
3fc0a319 75#if defined(KADB)
15637ed4 76extern cngetc(); /* standard console getc */
a201cfde
RG
77#endif
78#ifdef KADB
15637ed4
RG
79int (*v_getc)() = cngetc; /* "" getc from virtual console */
80extern cnpoll();
81int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */
82#endif
83extern cnputc(); /* standard console putc */
84int (*v_putc)() = cnputc; /* routine to putc on virtual console */
85
86static void logpri __P((int level));
87static void putchar __P((int ch, int flags, struct tty *tp));
88static char *ksprintn __P((u_long num, int base, int *len));
89void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list));
90
91/*
92 * Variable panicstr contains argument to first call to panic; used
93 * as flag to indicate that the kernel has already called panic.
94 */
a201cfde
RG
95const char *panicstr;
96
97/*
98 * Message buffer
99 */
100struct msgbuf *msgbufp;
101int msgbufmapped;
15637ed4
RG
102
103/*
104 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
105 * and then reboots. If we are called twice, then we avoid trying to sync
106 * the disks as this often leads to recursive panics.
107 */
108void
87b845cf 109panic(const char *msg)
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
fde1aeb2 132 Debugger ("panic");
15637ed4
RG
133#endif
134 boot(bootopt);
135}
136
137/*
138 * Warn that a system table is full.
139 */
140void
141tablefull(tab)
fde1aeb2 142 const char *tab;
15637ed4
RG
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
fde1aeb2 288void
15637ed4
RG
289#ifdef __STDC__
290addlog(const char *fmt, ...)
291#else
292addlog(fmt /*, va_alist */)
fde1aeb2 293 const char *fmt;
15637ed4
RG
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();
310}
311
312int consintr = 1; /* ok to handle console interrupts? */
313
a201cfde 314int
15637ed4
RG
315#ifdef __STDC__
316printf(const char *fmt, ...)
317#else
318printf(fmt /*, va_alist */)
fde1aeb2 319 const char *fmt;
15637ed4
RG
320#endif
321{
322 va_list ap;
323 register int savintr;
324
325 savintr = consintr; /* disable interrupts */
326 consintr = 0;
327 va_start(ap, fmt);
328 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
329 va_end(ap);
330 if (!panicstr)
331 logwakeup();
332 consintr = savintr; /* reenable interrupts */
a201cfde
RG
333
334 return 0; /* for compatibility with libc's printf() */
15637ed4
RG
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 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
354 *
355 * would produce output:
356 *
357 * reg=3<BITTWO,BITONE>
358 *
359 * The format %r is supposed to pass an additional format string and argument
360 * list recursively.
361 * Its usage is:
362 *
363 * fn(otherstuff, char *fmt, ...)
364 * {
365 * va_list ap;
366 * va_start(ap, fmt);
367 * printf("prefix: %r, other stuff\n", fmt, ap);
368 * va_end(ap);
369 *
370 * Space or zero padding and a field width are supported for the numeric
371 * formats only.
372 */
373void
374kprintf(fmt, flags, tp, ap)
375 register const char *fmt;
376 int flags;
377 struct tty *tp;
378 va_list ap;
379{
a201cfde 380 register char *p, *p2;
15637ed4
RG
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;
395reswitch: 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 *);
a201cfde 414 for (p2 = ksprintn(ul, *p++, NULL); ch = *p2--;)
15637ed4
RG
415 putchar(ch, flags, tp);
416
417 if (!ul)
418 break;
419
420 for (tmp = 0; n = *p++;) {
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 }
429 if (tmp)
430 putchar('>', flags, tp);
431 break;
432 case 'c':
433 putchar(va_arg(ap, int), flags, tp);
434 break;
435 case 'r':
436 p = va_arg(ap, char *);
437 kprintf(p, flags, tp, va_arg(ap, va_list));
438 break;
439 case 's':
440 p = va_arg(ap, char *);
441 while (ch = *p++)
442 putchar(ch, flags, tp);
443 break;
444 case 'd':
445 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
446 if ((long)ul < 0) {
447 putchar('-', flags, tp);
448 ul = -(long)ul;
449 }
450 base = 10;
451 goto number;
452 case 'o':
453 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
454 base = 8;
455 goto number;
456 case 'u':
457 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
458 base = 10;
459 goto number;
460 case 'x':
461 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
462 base = 16;
463number: p = ksprintn(ul, base, &tmp);
464 if (width && (width -= tmp) > 0)
465 while (width--)
466 putchar(padc, flags, tp);
467 while (ch = *p--)
468 putchar(ch, flags, tp);
469 break;
470 default:
471 putchar('%', flags, tp);
472 if (lflag)
473 putchar('l', flags, tp);
474 /* FALLTHROUGH */
475 case '%':
476 putchar(ch, flags, tp);
477 }
478 }
479}
480
481/*
482 * Print a character on console or users terminal. If destination is
483 * the console then the last MSGBUFS characters are saved in msgbuf for
484 * inspection later.
485 */
486static void
487putchar(c, flags, tp)
488 register int c;
489 int flags;
490 struct tty *tp;
491{
15637ed4
RG
492 register struct msgbuf *mbp;
493
494 if (panicstr)
495 constty = NULL;
496 if ((flags & TOCONS) && tp == NULL && constty) {
497 tp = constty;
498 flags |= TOTTY;
499 }
500 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
501 (flags & TOCONS) && tp == constty)
502 constty = NULL;
503 if ((flags & TOLOG) &&
504 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
505 mbp = msgbufp;
506 if (mbp->msg_magic != MSG_MAGIC) {
507 bzero((caddr_t)mbp, sizeof(*mbp));
508 mbp->msg_magic = MSG_MAGIC;
509 }
510 mbp->msg_bufc[mbp->msg_bufx++] = c;
511 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
512 mbp->msg_bufx = 0;
513 }
514 if ((flags & TOCONS) && constty == NULL && c != '\0')
515 (*v_putc)(c);
516}
517
518/*
519 * Scaled down version of sprintf(3).
520 */
521#ifdef __STDC__
a201cfde 522int
15637ed4
RG
523sprintf(char *buf, const char *cfmt, ...)
524#else
a201cfde 525int
15637ed4
RG
526sprintf(buf, cfmt /*, va_alist */)
527 char *buf, *cfmt;
528#endif
529{
530 register const char *fmt = cfmt;
531 register char *p, *bp;
532 register int ch, base;
533 u_long ul;
534 int lflag;
535 va_list ap;
536
537 va_start(ap, cfmt);
538 for (bp = buf; ; ) {
539 while ((ch = *(u_char *)fmt++) != '%')
540 if ((*bp++ = ch) == '\0')
541 return ((bp - buf) - 1);
542
543 lflag = 0;
544reswitch: switch (ch = *(u_char *)fmt++) {
545 case 'l':
546 lflag = 1;
547 goto reswitch;
548 case 'c':
549 *bp++ = va_arg(ap, int);
550 break;
551 case 's':
552 p = va_arg(ap, char *);
553 while (*bp++ = *p++)
554 ;
555 --bp;
556 break;
557 case 'd':
558 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
559 if ((long)ul < 0) {
560 *bp++ = '-';
561 ul = -(long)ul;
562 }
563 base = 10;
564 goto number;
565 break;
566 case 'o':
567 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
568 base = 8;
569 goto number;
570 break;
571 case 'u':
572 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
573 base = 10;
574 goto number;
575 break;
576 case 'x':
577 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
578 base = 16;
579number: for (p = ksprintn(ul, base, NULL); ch = *p--;)
580 *bp++ = ch;
581 break;
582 default:
583 *bp++ = '%';
584 if (lflag)
585 *bp++ = 'l';
586 /* FALLTHROUGH */
587 case '%':
588 *bp++ = ch;
589 }
590 }
591 va_end(ap);
592}
593
594/*
595 * Put a number (base <= 16) in a buffer in reverse order; return an
596 * optional length and a pointer to the NULL terminated (preceded?)
597 * buffer.
598 */
599static char *
600ksprintn(ul, base, lenp)
601 register u_long ul;
602 register int base, *lenp;
603{ /* A long in base 8, plus NULL. */
604 static char buf[sizeof(long) * NBBY / 3 + 2];
605 register char *p;
606
607 p = buf;
608 do {
609 *++p = "0123456789abcdef"[ul % base];
610 } while (ul /= base);
611 if (lenp)
612 *lenp = p - buf;
613 return (p);
614}