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