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