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