Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
e018935f | 2 | * Copyright (c) 1982, 1986, 1988 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
53276cec | 6 | * @(#)subr_prf.c 7.17 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
8cbb423c | 8 | |
94368568 JB |
9 | #include "param.h" |
10 | #include "systm.h" | |
11 | #include "seg.h" | |
12 | #include "buf.h" | |
13 | #include "conf.h" | |
14 | #include "reboot.h" | |
15 | #include "vm.h" | |
16 | #include "msgbuf.h" | |
94368568 JB |
17 | #include "user.h" |
18 | #include "proc.h" | |
3358b36b | 19 | #include "ioctl.h" |
71e86b6c MT |
20 | #include "vnode.h" |
21 | #include "file.h" | |
94368568 | 22 | #include "tty.h" |
bd10af3f | 23 | #include "syslog.h" |
96d38f03 | 24 | |
40ed2c45 | 25 | #include "machine/mtpr.h" |
f7f8b75f | 26 | #ifdef KADB |
40ed2c45 | 27 | #include "machine/kdbparam.h" |
3eb8e016 MK |
28 | #endif |
29 | ||
34ef3482 RC |
30 | #define TOCONS 0x1 |
31 | #define TOTTY 0x2 | |
32 | #define TOLOG 0x4 | |
33 | ||
8cbb423c BJ |
34 | /* |
35 | * In case console is off, | |
36 | * panicstr contains argument to last | |
37 | * call to panic. | |
38 | */ | |
8cbb423c BJ |
39 | char *panicstr; |
40 | ||
ed2d0915 | 41 | extern cnputc(); /* standard console putc */ |
ae032917 | 42 | int (*v_putc)() = cnputc; /* routine to putc on virtual console */ |
ed2d0915 MK |
43 | extern struct tty cons; /* standard console tty */ |
44 | struct tty *constty; /* pointer to console "window" tty */ | |
ae032917 MT |
45 | |
46 | #ifdef KADB | |
47 | extern cngetc(); /* standard console getc */ | |
48 | extern cnpoll(); | |
49 | int (*v_getc)() = cngetc; /* "" getc from virtual console */ | |
50 | int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */ | |
51 | #endif | |
ed2d0915 | 52 | |
1d4b2ce4 MK |
53 | extern cnputc(); /* standard console putc */ |
54 | extern struct tty cons; /* standard console tty */ | |
55 | struct tty *constty; /* pointer to console "window" tty */ | |
56 | int (*v_console)() = cnputc; /* routine to putc on virtual console */ | |
57 | ||
8cbb423c BJ |
58 | /* |
59 | * Scaled down version of C Library printf. | |
b725a0ca BJ |
60 | * Used to print diagnostic information directly on console tty. |
61 | * Since it is not interrupt driven, all system activities are | |
62 | * suspended. Printf should not be used for chit-chat. | |
63 | * | |
64 | * One additional format: %b is supported to decode error registers. | |
65 | * Usage is: | |
66 | * printf("reg=%b\n", regval, "<base><arg>*"); | |
67 | * Where <base> is the output base expressed as a control character, | |
68 | * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of | |
69 | * characters, the first of which gives the bit number to be inspected | |
70 | * (origin 1), and the next characters (up to a control character, i.e. | |
71 | * a character <= 32), give the name of the register. Thus | |
72 | * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); | |
73 | * would produce output: | |
8d907ccf | 74 | * reg=3<BITTWO,BITONE> |
6a79e262 MK |
75 | * |
76 | * Another additional format: %r is used to pass an additional format string | |
77 | * and argument list recursively. Usage is typically: | |
78 | * | |
79 | * fn(otherstuff, fmt [, arg1, ... ] ) | |
80 | * char *fmt; | |
81 | * u_int arg1, ...; | |
82 | * | |
83 | * printf("prefix: %r, other stuff\n", fmt, &arg1); | |
8cbb423c | 84 | */ |
fb1db32c MK |
85 | #if defined(tahoe) |
86 | int consintr; | |
87 | #endif | |
88 | ||
8cbb423c BJ |
89 | /*VARARGS1*/ |
90 | printf(fmt, x1) | |
b725a0ca BJ |
91 | char *fmt; |
92 | unsigned x1; | |
96d38f03 | 93 | { |
fb1db32c MK |
94 | #if defined(tahoe) |
95 | register int savintr; | |
96d38f03 | 96 | |
fb1db32c MK |
97 | savintr = consintr, consintr = 0; /* disable interrupts */ |
98 | #endif | |
71e86b6c | 99 | prf(fmt, &x1, TOCONS | TOLOG, (caddr_t)0); |
53276cec KM |
100 | if (!panicstr) |
101 | logwakeup(); | |
fb1db32c MK |
102 | #if defined(tahoe) |
103 | consintr = savintr; /* reenable interrupts */ | |
104 | #endif | |
96d38f03 BJ |
105 | } |
106 | ||
843267b1 | 107 | /* |
71e86b6c | 108 | * Uprintf prints to the controlling terminal for the current process. |
6f71a9f6 | 109 | * It may block if the tty queue is overfull. |
ca9b16e5 MK |
110 | * No message is printed if the queue does not clear |
111 | * in a reasonable time. | |
843267b1 BJ |
112 | */ |
113 | /*VARARGS1*/ | |
114 | uprintf(fmt, x1) | |
b725a0ca | 115 | char *fmt; |
843267b1 | 116 | unsigned x1; |
96d38f03 | 117 | { |
71e86b6c | 118 | register struct tty *tp = u.u_procp->p_session->s_ttyp; |
96d38f03 | 119 | |
71e86b6c | 120 | if (tp != NULL && tp->t_session == u.u_procp->p_session) |
53276cec | 121 | prf(fmt, &x1, TOTTY, (caddr_t)tp); |
34ef3482 RC |
122 | } |
123 | ||
bd10af3f MK |
124 | /* |
125 | * tprintf prints on the specified terminal (console if none) | |
126 | * and logs the message. It is designed for error messages from | |
6f71a9f6 MK |
127 | * single-open devices, and may be called from interrupt level |
128 | * (does not sleep). | |
bd10af3f | 129 | */ |
34ef3482 | 130 | /*VARARGS2*/ |
71e86b6c MT |
131 | tprintf(vp, fmt, x1) |
132 | register caddr_t vp; | |
34ef3482 RC |
133 | char *fmt; |
134 | unsigned x1; | |
135 | { | |
53276cec | 136 | #ifdef notyet |
6f71a9f6 | 137 | int flags = TOTTY | TOLOG; |
34ef3482 | 138 | |
6f71a9f6 | 139 | logpri(LOG_INFO); |
71e86b6c MT |
140 | |
141 | if (vp == NULL || | |
142 | VOP_IOCTL(vp, TIOCCHECKOUTQ, &val, FWRITE, NOCRED) != 0 || | |
143 | val == 0) | |
6f71a9f6 | 144 | flags = TOLOG; |
71e86b6c | 145 | prf(fmt, &x1, flags, vp); |
6f71a9f6 | 146 | logwakeup(); |
71e86b6c MT |
147 | #else |
148 | printf("tprintf called\n"); | |
149 | #endif | |
34ef3482 RC |
150 | } |
151 | ||
152 | /* | |
153 | * Log writes to the log buffer, | |
8d907ccf | 154 | * and guarantees not to sleep (so can be called by interrupt routines). |
bd10af3f | 155 | * If there is no process reading the log yet, it writes to the console also. |
34ef3482 RC |
156 | */ |
157 | /*VARARGS2*/ | |
158 | log(level, fmt, x1) | |
159 | char *fmt; | |
160 | unsigned x1; | |
161 | { | |
162 | register s = splhigh(); | |
bd10af3f | 163 | extern int log_open; |
34ef3482 | 164 | |
6f71a9f6 | 165 | logpri(level); |
71e86b6c | 166 | prf(fmt, &x1, TOLOG, (caddr_t)0); |
34ef3482 | 167 | splx(s); |
bd10af3f | 168 | if (!log_open) |
71e86b6c | 169 | prf(fmt, &x1, TOCONS, (caddr_t)0); |
34ef3482 | 170 | logwakeup(); |
96d38f03 BJ |
171 | } |
172 | ||
6f71a9f6 MK |
173 | logpri(level) |
174 | int level; | |
175 | { | |
176 | ||
53276cec KM |
177 | putchar('<', TOLOG, (caddr_t)0); |
178 | printn((u_long)level, 10, TOLOG, (caddr_t)0); | |
179 | putchar('>', TOLOG, (caddr_t)0); | |
6f71a9f6 MK |
180 | } |
181 | ||
c55a3dd0 MK |
182 | /*VARARGS1*/ |
183 | addlog(fmt, x1) | |
184 | char *fmt; | |
185 | unsigned x1; | |
186 | { | |
187 | register s = splhigh(); | |
188 | ||
71e86b6c | 189 | prf(fmt, &x1, TOLOG, (caddr_t)0); |
c55a3dd0 MK |
190 | splx(s); |
191 | if (!log_open) | |
71e86b6c | 192 | prf(fmt, &x1, TOCONS, (caddr_t)0); |
c55a3dd0 MK |
193 | logwakeup(); |
194 | } | |
195 | ||
71e86b6c | 196 | prf(fmt, adx, flags, where) |
b725a0ca BJ |
197 | register char *fmt; |
198 | register u_int *adx; | |
71e86b6c | 199 | caddr_t where; |
8cbb423c | 200 | { |
d5726689 | 201 | register int b, c, i; |
8cbb423c | 202 | char *s; |
3c79e4ff | 203 | int any; |
8cbb423c | 204 | |
8cbb423c | 205 | loop: |
843267b1 | 206 | while ((c = *fmt++) != '%') { |
34ef3482 | 207 | if (c == '\0') |
8cbb423c | 208 | return; |
71e86b6c | 209 | putchar(c, flags, where); |
8cbb423c | 210 | } |
843267b1 | 211 | again: |
8cbb423c | 212 | c = *fmt++; |
fb1db32c | 213 | /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ |
843267b1 BJ |
214 | switch (c) { |
215 | ||
216 | case 'l': | |
217 | goto again; | |
218 | case 'x': case 'X': | |
219 | b = 16; | |
220 | goto number; | |
221 | case 'd': case 'D': | |
fb1db32c MK |
222 | b = -10; |
223 | goto number; | |
224 | case 'u': | |
843267b1 BJ |
225 | b = 10; |
226 | goto number; | |
227 | case 'o': case 'O': | |
228 | b = 8; | |
229 | number: | |
71e86b6c | 230 | printn((u_long)*adx, b, flags, where); |
843267b1 BJ |
231 | break; |
232 | case 'c': | |
d5726689 | 233 | b = *adx; |
c55a3dd0 | 234 | #if BYTE_ORDER == LITTLE_ENDIAN |
d5726689 BJ |
235 | for (i = 24; i >= 0; i -= 8) |
236 | if (c = (b >> i) & 0x7f) | |
71e86b6c | 237 | putchar(c, flags, where); |
fb1db32c | 238 | #endif |
c55a3dd0 | 239 | #if BYTE_ORDER == BIG_ENDIAN |
fb1db32c | 240 | if (c = (b & 0x7f)) |
71e86b6c | 241 | putchar(c, flags, where); |
fb1db32c | 242 | #endif |
843267b1 | 243 | break; |
3c79e4ff BJ |
244 | case 'b': |
245 | b = *adx++; | |
246 | s = (char *)*adx; | |
71e86b6c | 247 | printn((u_long)b, *s++, flags, where); |
3c79e4ff BJ |
248 | any = 0; |
249 | if (b) { | |
3c79e4ff BJ |
250 | while (i = *s++) { |
251 | if (b & (1 << (i-1))) { | |
71e86b6c | 252 | putchar(any ? ',' : '<', flags, where); |
3c79e4ff BJ |
253 | any = 1; |
254 | for (; (c = *s) > 32; s++) | |
71e86b6c | 255 | putchar(c, flags, where); |
3c79e4ff BJ |
256 | } else |
257 | for (; *s > 32; s++) | |
258 | ; | |
259 | } | |
1ce587f2 | 260 | if (any) |
71e86b6c | 261 | putchar('>', flags, where); |
3c79e4ff BJ |
262 | } |
263 | break; | |
264 | ||
843267b1 | 265 | case 's': |
8cbb423c | 266 | s = (char *)*adx; |
96d38f03 | 267 | while (c = *s++) |
71e86b6c | 268 | putchar(c, flags, where); |
843267b1 | 269 | break; |
2bb8d359 | 270 | |
c55a3dd0 MK |
271 | case 'r': |
272 | s = (char *)*adx++; | |
71e86b6c | 273 | prf(s, (u_int *)*adx, flags, where); |
c55a3dd0 MK |
274 | break; |
275 | ||
2bb8d359 | 276 | case '%': |
71e86b6c | 277 | putchar('%', flags, where); |
2bb8d359 | 278 | break; |
8cbb423c BJ |
279 | } |
280 | adx++; | |
281 | goto loop; | |
282 | } | |
283 | ||
b725a0ca BJ |
284 | /* |
285 | * Printn prints a number n in base b. | |
286 | * We don't use recursion to avoid deep kernel stacks. | |
287 | */ | |
71e86b6c | 288 | printn(n, b, flags, where) |
a0eab615 | 289 | u_long n; |
71e86b6c | 290 | caddr_t where; |
8cbb423c | 291 | { |
d5726689 | 292 | char prbuf[11]; |
843267b1 | 293 | register char *cp; |
8cbb423c | 294 | |
fb1db32c MK |
295 | if (b == -10) { |
296 | if ((int)n < 0) { | |
71e86b6c | 297 | putchar('-', flags, where); |
fb1db32c MK |
298 | n = (unsigned)(-(int)n); |
299 | } | |
300 | b = -b; | |
8cbb423c | 301 | } |
d5726689 | 302 | cp = prbuf; |
843267b1 BJ |
303 | do { |
304 | *cp++ = "0123456789abcdef"[n%b]; | |
305 | n /= b; | |
306 | } while (n); | |
307 | do | |
71e86b6c | 308 | putchar(*--cp, flags, where); |
d5726689 | 309 | while (cp > prbuf); |
8cbb423c BJ |
310 | } |
311 | ||
312 | /* | |
0dc06be8 | 313 | * Panic is called on unresolvable fatal errors. |
b725a0ca BJ |
314 | * It prints "panic: mesg", and then reboots. |
315 | * If we are called twice, then we avoid trying to | |
316 | * sync the disks as this often leads to recursive panics. | |
8cbb423c BJ |
317 | */ |
318 | panic(s) | |
b725a0ca | 319 | char *s; |
8cbb423c | 320 | { |
295184b1 | 321 | int bootopt = RB_AUTOBOOT | RB_DUMP; |
843267b1 | 322 | |
68503f9a BJ |
323 | if (panicstr) |
324 | bootopt |= RB_NOSYNC; | |
cddce008 | 325 | else { |
961945a8 | 326 | panicstr = s; |
961945a8 | 327 | } |
a9c526c1 | 328 | printf("panic: %s\n", s); |
f7f8b75f | 329 | #ifdef KADB |
3eb8e016 | 330 | if (boothowto & RB_KDB) { |
e018935f | 331 | int x = splnet(); /* below kdb pri */ |
3eb8e016 MK |
332 | |
333 | setsoftkdb(); | |
e018935f | 334 | splx(x); |
3eb8e016 MK |
335 | } |
336 | #endif | |
295184b1 | 337 | boot(bootopt); |
8cbb423c BJ |
338 | } |
339 | ||
fdd11a14 BJ |
340 | /* |
341 | * Warn that a system table is full. | |
342 | */ | |
343 | tablefull(tab) | |
344 | char *tab; | |
345 | { | |
346 | ||
283ffc90 | 347 | log(LOG_ERR, "%s: table is full\n", tab); |
fdd11a14 BJ |
348 | } |
349 | ||
96d38f03 | 350 | /* |
843267b1 | 351 | * Print a character on console or users terminal. |
96d38f03 BJ |
352 | * If destination is console then the last MSGBUFS characters |
353 | * are saved in msgbuf for inspection later. | |
354 | */ | |
49c84d3f | 355 | /*ARGSUSED*/ |
71e86b6c | 356 | putchar(c, flags, where) |
843267b1 | 357 | register int c; |
71e86b6c | 358 | caddr_t where; |
96d38f03 | 359 | { |
c55a3dd0 | 360 | extern int msgbufmapped; |
96d38f03 | 361 | |
ed2d0915 MK |
362 | if (panicstr) |
363 | constty = 0; | |
71e86b6c MT |
364 | if ((flags & TOCONS) && where == 0 && constty) { |
365 | where = (caddr_t)constty; | |
ed2d0915 MK |
366 | flags |= TOTTY; |
367 | } | |
1d4b2ce4 MK |
368 | if ((flags & TOCONS) && panicstr == 0 && tp == 0 && constty) { |
369 | tp = constty; | |
370 | flags |= TOTTY; | |
371 | } | |
71e86b6c MT |
372 | if ((flags & TOTTY) && where && tputchar(c, (struct tty *)where) < 0 && |
373 | (flags & TOCONS) && (struct tty *)where == constty) | |
374 | constty = 0; | |
c55a3dd0 MK |
375 | if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && |
376 | msgbufmapped) { | |
90f8d91f | 377 | if (msgbuf.msg_magic != MSG_MAGIC) { |
76db4195 SL |
378 | register int i; |
379 | ||
90f8d91f | 380 | msgbuf.msg_magic = MSG_MAGIC; |
34ef3482 | 381 | msgbuf.msg_bufx = msgbuf.msg_bufr = 0; |
76db4195 SL |
382 | for (i=0; i < MSG_BSIZE; i++) |
383 | msgbuf.msg_bufc[i] = 0; | |
90f8d91f | 384 | } |
7e401e0e | 385 | msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; |
90f8d91f BJ |
386 | if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) |
387 | msgbuf.msg_bufx = 0; | |
96d38f03 | 388 | } |
1d4b2ce4 | 389 | (*v_console)(c); |
96d38f03 | 390 | } |