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