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