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