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