use inb and outb from locore
[unix-history] / usr / src / sys / kern / subr_prf.c
CommitLineData
f324a387 1/*-
c34daa85
KB
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
f324a387
KB
4 *
5 * %sccs.include.redist.c%
da7c5cc6 6 *
c34daa85 7 * @(#)subr_prf.c 8.1 (Berkeley) %G%
da7c5cc6 8 */
8cbb423c 9
ed782152
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/buf.h>
13#include <sys/conf.h>
14#include <sys/reboot.h>
15#include <sys/msgbuf.h>
16#include <sys/proc.h>
17#include <sys/ioctl.h>
18#include <sys/vnode.h>
19#include <sys/file.h>
20#include <sys/tty.h>
21#include <sys/tprintf.h>
22#include <sys/syslog.h>
23#include <sys/malloc.h>
96d38f03 24
f324a387
KB
25/*
26 * Note that stdarg.h and the ANSI style va_start macro is used for both
27 * ANSI and traditional C compilers.
28 */
29#include <machine/stdarg.h>
30
f7f8b75f 31#ifdef KADB
38a01dbe 32#include <machine/kdbparam.h>
3eb8e016
MK
33#endif
34
f324a387
KB
35#define TOCONS 0x01
36#define TOTTY 0x02
37#define TOLOG 0x04
34ef3482 38
ed2d0915 39struct tty *constty; /* pointer to console "window" tty */
ae032917 40
f324a387 41extern cnputc(); /* standard console putc */
f26dc35a 42int (*v_putc)() = cnputc; /* routine to putc on virtual console */
f324a387 43
890fb5ad 44void logpri __P((int level));
d4339c84 45static void putchar __P((int ch, int flags, struct tty *tp));
d4339c84 46static char *ksprintn __P((u_long num, int base, int *len));
c77828a2 47void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
ed782152
KB
48
49int consintr = 1; /* Ok to handle console interrupts? */
ed2d0915 50
1d4b2ce4
MK
51extern cnputc(); /* standard console putc */
52extern struct tty cons; /* standard console tty */
53struct tty *constty; /* pointer to console "window" tty */
54int (*v_console)() = cnputc; /* routine to putc on virtual console */
55
8cbb423c 56/*
ed782152
KB
57 * Variable panicstr contains argument to first call to panic; used as flag
58 * to indicate that the kernel has already called panic.
8cbb423c 59 */
ed782152 60const char *panicstr;
3e199d90 61
f324a387
KB
62/*
63 * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
64 * and then reboots. If we are called twice, then we avoid trying to sync
65 * the disks as this often leads to recursive panics.
66 */
c77828a2 67#ifdef __GNUC__
ea95b3cd 68volatile void boot(int flags); /* boot() does not return */
c77828a2
MT
69volatile /* panic() does not return */
70#endif
f324a387 71void
ed782152
KB
72#ifdef __STDC__
73panic(const char *fmt, ...)
74#else
08901f4a 75panic(fmt, va_alist)
ed782152
KB
76 char *fmt;
77#endif
f324a387 78{
c77828a2 79 int bootopt;
ed782152 80 va_list ap;
fb1db32c 81
ed782152 82 bootopt = RB_AUTOBOOT | RB_DUMP;
f324a387
KB
83 if (panicstr)
84 bootopt |= RB_NOSYNC;
85 else
ed782152
KB
86 panicstr = fmt;
87
ed782152 88 va_start(ap, fmt);
c77828a2 89 printf("panic: %r\n", fmt, ap);
ed782152
KB
90 va_end(ap);
91
f324a387
KB
92#ifdef KGDB
93 kgdb_panic();
94#endif
95#ifdef KADB
08901f4a
RC
96 if (boothowto & RB_KDB)
97 kdbpanic();
f324a387
KB
98#endif
99 boot(bootopt);
100}
101
102/*
103 * Warn that a system table is full.
104 */
105void
106tablefull(tab)
ea95b3cd 107 const char *tab;
96d38f03
BJ
108{
109
f324a387 110 log(LOG_ERR, "%s: table is full\n", tab);
96d38f03
BJ
111}
112
843267b1 113/*
71e86b6c 114 * Uprintf prints to the controlling terminal for the current process.
f324a387
KB
115 * It may block if the tty queue is overfull. No message is printed if
116 * the queue does not clear in a reasonable time.
843267b1 117 */
f324a387
KB
118void
119#ifdef __STDC__
120uprintf(const char *fmt, ...)
121#else
6534ed0a 122uprintf(fmt, va_alist)
b725a0ca 123 char *fmt;
f324a387 124#endif
96d38f03 125{
8429d022 126 register struct proc *p = curproc;
f324a387 127 va_list ap;
96d38f03 128
f26dc35a
KB
129 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
130 va_start(ap, fmt);
f324a387 131 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
f26dc35a
KB
132 va_end(ap);
133 }
35dc415e
MT
134}
135
136tpr_t
3e199d90
MK
137tprintf_open(p)
138 register struct proc *p;
35dc415e 139{
f26dc35a 140
35dc415e
MT
141 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
142 SESSHOLD(p->p_session);
3e199d90 143 return ((tpr_t) p->p_session);
f324a387
KB
144 }
145 return ((tpr_t) NULL);
35dc415e
MT
146}
147
3e199d90 148void
35dc415e
MT
149tprintf_close(sess)
150 tpr_t sess;
151{
f26dc35a 152
35dc415e 153 if (sess)
3e199d90 154 SESSRELE((struct session *) sess);
34ef3482
RC
155}
156
bd10af3f 157/*
35dc415e 158 * tprintf prints on the controlling terminal associated
f324a387 159 * with the given session.
bd10af3f 160 */
f324a387
KB
161void
162#ifdef __STDC__
163tprintf(tpr_t tpr, const char *fmt, ...)
164#else
6534ed0a 165tprintf(tpr, fmt, va_alist)
3e199d90 166 tpr_t tpr;
34ef3482 167 char *fmt;
f324a387 168#endif
34ef3482 169{
3e199d90
MK
170 register struct session *sess = (struct session *)tpr;
171 struct tty *tp = NULL;
35dc415e 172 int flags = TOLOG;
f324a387 173 va_list ap;
34ef3482 174
6f71a9f6 175 logpri(LOG_INFO);
3e199d90 176 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
35dc415e 177 flags |= TOTTY;
3e199d90
MK
178 tp = sess->s_ttyp;
179 }
f324a387
KB
180 va_start(ap, fmt);
181 kprintf(fmt, flags, tp, ap);
182 va_end(ap);
6f71a9f6 183 logwakeup();
34ef3482
RC
184}
185
f324a387
KB
186/*
187 * Ttyprintf displays a message on a tty; it should be used only by
188 * the tty driver, or anything that knows the underlying tty will not
189 * be revoke(2)'d away. Other callers should use tprintf.
190 */
191void
192#ifdef __STDC__
193ttyprintf(struct tty *tp, const char *fmt, ...)
194#else
6534ed0a 195ttyprintf(tp, fmt, va_alist)
f324a387
KB
196 struct tty *tp;
197 char *fmt;
198#endif
199{
200 va_list ap;
201
202 va_start(ap, fmt);
203 kprintf(fmt, TOTTY, tp, ap);
204 va_end(ap);
205}
206
3e199d90 207extern int log_open;
35dc415e 208
34ef3482 209/*
f324a387
KB
210 * Log writes to the log buffer, and guarantees not to sleep (so can be
211 * called by interrupt routines). If there is no process reading the
212 * log yet, it writes to the console also.
34ef3482 213 */
f324a387
KB
214void
215#ifdef __STDC__
216log(int level, const char *fmt, ...)
217#else
6534ed0a 218log(level, fmt, va_alist)
f324a387 219 int level;
34ef3482 220 char *fmt;
f324a387 221#endif
34ef3482 222{
293eb5c9 223 register int s;
f324a387 224 va_list ap;
34ef3482 225
293eb5c9 226 s = splhigh();
6f71a9f6 227 logpri(level);
f324a387
KB
228 va_start(ap, fmt);
229 kprintf(fmt, TOLOG, NULL, ap);
34ef3482 230 splx(s);
f324a387 231 va_end(ap);
f26dc35a
KB
232 if (!log_open) {
233 va_start(ap, fmt);
234 kprintf(fmt, TOCONS, NULL, ap);
235 va_end(ap);
236 }
34ef3482 237 logwakeup();
96d38f03
BJ
238}
239
890fb5ad 240void
6f71a9f6
MK
241logpri(level)
242 int level;
243{
d4339c84
KB
244 register int ch;
245 register char *p;
6f71a9f6 246
f324a387 247 putchar('<', TOLOG, NULL);
d4339c84
KB
248 for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
249 putchar(ch, TOLOG, NULL);
f324a387 250 putchar('>', TOLOG, NULL);
6f71a9f6
MK
251}
252
f324a387
KB
253void
254#ifdef __STDC__
255addlog(const char *fmt, ...)
256#else
6534ed0a 257addlog(fmt, va_alist)
c55a3dd0 258 char *fmt;
f324a387 259#endif
c55a3dd0 260{
293eb5c9 261 register int s;
f324a387 262 va_list ap;
c55a3dd0 263
293eb5c9 264 s = splhigh();
f324a387
KB
265 va_start(ap, fmt);
266 kprintf(fmt, TOLOG, NULL, ap);
c55a3dd0 267 splx(s);
f324a387 268 va_end(ap);
f26dc35a
KB
269 if (!log_open) {
270 va_start(ap, fmt);
271 kprintf(fmt, TOCONS, NULL, ap);
272 va_end(ap);
273 }
c55a3dd0
MK
274 logwakeup();
275}
276
f324a387
KB
277void
278#ifdef __STDC__
279printf(const char *fmt, ...)
280#else
6534ed0a 281printf(fmt, va_alist)
f324a387
KB
282 char *fmt;
283#endif
8cbb423c 284{
f324a387 285 va_list ap;
f26dc35a 286 register int savintr;
8cbb423c 287
f324a387
KB
288 savintr = consintr; /* disable interrupts */
289 consintr = 0;
290 va_start(ap, fmt);
291 kprintf(fmt, TOCONS | TOLOG, NULL, ap);
292 va_end(ap);
293 if (!panicstr)
294 logwakeup();
295 consintr = savintr; /* reenable interrupts */
8cbb423c
BJ
296}
297
298/*
f324a387
KB
299 * Scaled down version of printf(3).
300 *
301 * Two additional formats:
302 *
303 * The format %b is supported to decode error registers.
304 * Its usage is:
305 *
c77828a2 306 * printf("reg=%b\n", regval, "<base><arg>*");
f324a387
KB
307 *
308 * where <base> is the output base expressed as a control character, e.g.
309 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
310 * the first of which gives the bit number to be inspected (origin 1), and
311 * the next characters (up to a control character, i.e. a character <= 32),
312 * give the name of the register. Thus:
313 *
ed782152 314 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
f324a387
KB
315 *
316 * would produce output:
317 *
318 * reg=3<BITTWO,BITONE>
319 *
ed782152
KB
320 * The format %r passes an additional format string and argument list
321 * recursively. Its usage is:
f324a387 322 *
ed782152 323 * fn(char *fmt, ...)
f26dc35a
KB
324 * {
325 * va_list ap;
326 * va_start(ap, fmt);
c77828a2 327 * printf("prefix: %r: suffix\n", fmt, ap);
f26dc35a 328 * va_end(ap);
ed782152 329 * }
d4339c84
KB
330 *
331 * Space or zero padding and a field width are supported for the numeric
332 * formats only.
8cbb423c 333 */
106a3d16 334void
c77828a2 335kprintf(fmt, flags, tp, ap)
8345edbf 336 register const char *fmt;
f324a387 337 int flags;
8345edbf 338 struct tty *tp;
f324a387 339 va_list ap;
8cbb423c 340{
40a0752a 341 register char *p, *q;
f324a387 342 register int ch, n;
d4339c84
KB
343 u_long ul;
344 int base, lflag, tmp, width;
345 char padc;
f324a387
KB
346
347 for (;;) {
d4339c84
KB
348 padc = ' ';
349 width = 0;
8b22ea34 350 while ((ch = *(u_char *)fmt++) != '%') {
f324a387
KB
351 if (ch == '\0')
352 return;
8345edbf 353 putchar(ch, flags, tp);
f324a387
KB
354 }
355 lflag = 0;
8b22ea34 356reswitch: switch (ch = *(u_char *)fmt++) {
d4339c84
KB
357 case '0':
358 padc = '0';
359 goto reswitch;
360 case '1': case '2': case '3': case '4':
361 case '5': case '6': case '7': case '8': case '9':
362 for (width = 0;; ++fmt) {
363 width = width * 10 + ch - '0';
364 ch = *fmt;
365 if (ch < '0' || ch > '9')
366 break;
367 }
368 goto reswitch;
f324a387
KB
369 case 'l':
370 lflag = 1;
371 goto reswitch;
372 case 'b':
373 ul = va_arg(ap, int);
374 p = va_arg(ap, char *);
40a0752a 375 for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
d4339c84 376 putchar(ch, flags, tp);
f324a387
KB
377
378 if (!ul)
379 break;
380
d4339c84 381 for (tmp = 0; n = *p++;) {
f324a387 382 if (ul & (1 << (n - 1))) {
d4339c84 383 putchar(tmp ? ',' : '<', flags, tp);
f324a387 384 for (; (n = *p) > ' '; ++p)
8345edbf 385 putchar(n, flags, tp);
d4339c84 386 tmp = 1;
f324a387 387 } else
a6e3920d
CT
388 for (; *p > ' '; ++p)
389 continue;
f324a387 390 }
d4339c84 391 if (tmp)
8345edbf 392 putchar('>', flags, tp);
f324a387
KB
393 break;
394 case 'c':
8345edbf 395 putchar(va_arg(ap, int), flags, tp);
f324a387
KB
396 break;
397 case 'r':
398 p = va_arg(ap, char *);
8345edbf 399 kprintf(p, flags, tp, va_arg(ap, va_list));
f324a387
KB
400 break;
401 case 's':
402 p = va_arg(ap, char *);
403 while (ch = *p++)
8345edbf 404 putchar(ch, flags, tp);
f324a387 405 break;
f324a387 406 case 'd':
d4339c84 407 ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
f324a387 408 if ((long)ul < 0) {
8345edbf 409 putchar('-', flags, tp);
f324a387
KB
410 ul = -(long)ul;
411 }
d4339c84
KB
412 base = 10;
413 goto number;
f324a387 414 case 'o':
d4339c84
KB
415 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
416 base = 8;
f26dc35a 417 goto number;
f324a387 418 case 'u':
d4339c84
KB
419 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
420 base = 10;
421 goto number;
f324a387 422 case 'x':
d4339c84
KB
423 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
424 base = 16;
425number: p = ksprintn(ul, base, &tmp);
426 if (width && (width -= tmp) > 0)
427 while (width--)
428 putchar(padc, flags, tp);
429 while (ch = *p--)
430 putchar(ch, flags, tp);
f324a387
KB
431 break;
432 default:
8345edbf 433 putchar('%', flags, tp);
f324a387 434 if (lflag)
8345edbf 435 putchar('l', flags, tp);
d4339c84
KB
436 /* FALLTHROUGH */
437 case '%':
8345edbf 438 putchar(ch, flags, tp);
f324a387 439 }
3eb8e016 440 }
8cbb423c
BJ
441}
442
96d38f03 443/*
f324a387
KB
444 * Print a character on console or users terminal. If destination is
445 * the console then the last MSGBUFS characters are saved in msgbuf for
446 * inspection later.
96d38f03 447 */
f324a387 448static void
8345edbf 449putchar(c, flags, tp)
843267b1 450 register int c;
f324a387 451 int flags;
8345edbf 452 struct tty *tp;
96d38f03 453{
c55a3dd0 454 extern int msgbufmapped;
293eb5c9 455 register struct msgbuf *mbp;
96d38f03 456
ed2d0915 457 if (panicstr)
f324a387 458 constty = NULL;
8345edbf
KB
459 if ((flags & TOCONS) && tp == NULL && constty) {
460 tp = constty;
ed2d0915
MK
461 flags |= TOTTY;
462 }
1d4b2ce4
MK
463 if ((flags & TOCONS) && panicstr == 0 && tp == 0 && constty) {
464 tp = constty;
465 flags |= TOTTY;
466 }
8345edbf
KB
467 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
468 (flags & TOCONS) && tp == constty)
f324a387
KB
469 constty = NULL;
470 if ((flags & TOLOG) &&
471 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
293eb5c9 472 mbp = msgbufp;
9db58063 473 if (mbp->msg_magic != MSG_MAGIC) {
f26dc35a 474 bzero((caddr_t)mbp, sizeof(*mbp));
9db58063 475 mbp->msg_magic = MSG_MAGIC;
90f8d91f 476 }
9db58063
KM
477 mbp->msg_bufc[mbp->msg_bufx++] = c;
478 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
479 mbp->msg_bufx = 0;
96d38f03 480 }
1d4b2ce4 481 (*v_console)(c);
96d38f03 482}