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 | * | |
2100bbbc | 6 | * @(#)subr_prf.c 7.14 (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" |
94368568 | 20 | #include "tty.h" |
bd10af3f | 21 | #include "syslog.h" |
96d38f03 | 22 | |
40ed2c45 | 23 | #include "machine/mtpr.h" |
f7f8b75f | 24 | #ifdef KADB |
40ed2c45 | 25 | #include "machine/kdbparam.h" |
3eb8e016 MK |
26 | #endif |
27 | ||
34ef3482 RC |
28 | #define TOCONS 0x1 |
29 | #define TOTTY 0x2 | |
30 | #define TOLOG 0x4 | |
31 | ||
8cbb423c BJ |
32 | /* |
33 | * In case console is off, | |
34 | * panicstr contains argument to last | |
35 | * call to panic. | |
36 | */ | |
8cbb423c BJ |
37 | char *panicstr; |
38 | ||
ed2d0915 MK |
39 | extern cnputc(); /* standard console putc */ |
40 | extern struct tty cons; /* standard console tty */ | |
41 | struct tty *constty; /* pointer to console "window" tty */ | |
42 | int (*v_putc)() = cnputc; /* routine to putc on virtual console */ | |
43 | ||
1d4b2ce4 MK |
44 | extern cnputc(); /* standard console putc */ |
45 | extern struct tty cons; /* standard console tty */ | |
46 | struct tty *constty; /* pointer to console "window" tty */ | |
47 | int (*v_console)() = cnputc; /* routine to putc on virtual console */ | |
48 | ||
8cbb423c BJ |
49 | /* |
50 | * Scaled down version of C Library printf. | |
b725a0ca BJ |
51 | * Used to print diagnostic information directly on console tty. |
52 | * Since it is not interrupt driven, all system activities are | |
53 | * suspended. Printf should not be used for chit-chat. | |
54 | * | |
55 | * One additional format: %b is supported to decode error registers. | |
56 | * Usage is: | |
57 | * printf("reg=%b\n", regval, "<base><arg>*"); | |
58 | * Where <base> is the output base expressed as a control character, | |
59 | * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of | |
60 | * characters, the first of which gives the bit number to be inspected | |
61 | * (origin 1), and the next characters (up to a control character, i.e. | |
62 | * a character <= 32), give the name of the register. Thus | |
63 | * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); | |
64 | * would produce output: | |
8d907ccf | 65 | * reg=3<BITTWO,BITONE> |
6a79e262 MK |
66 | * |
67 | * Another additional format: %r is used to pass an additional format string | |
68 | * and argument list recursively. Usage is typically: | |
69 | * | |
70 | * fn(otherstuff, fmt [, arg1, ... ] ) | |
71 | * char *fmt; | |
72 | * u_int arg1, ...; | |
73 | * | |
74 | * printf("prefix: %r, other stuff\n", fmt, &arg1); | |
8cbb423c | 75 | */ |
fb1db32c MK |
76 | #if defined(tahoe) |
77 | int consintr; | |
78 | #endif | |
79 | ||
8cbb423c BJ |
80 | /*VARARGS1*/ |
81 | printf(fmt, x1) | |
b725a0ca BJ |
82 | char *fmt; |
83 | unsigned x1; | |
96d38f03 | 84 | { |
fb1db32c MK |
85 | #if defined(tahoe) |
86 | register int savintr; | |
96d38f03 | 87 | |
fb1db32c MK |
88 | savintr = consintr, consintr = 0; /* disable interrupts */ |
89 | #endif | |
34ef3482 RC |
90 | prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0); |
91 | logwakeup(); | |
fb1db32c MK |
92 | #if defined(tahoe) |
93 | consintr = savintr; /* reenable interrupts */ | |
94 | #endif | |
96d38f03 BJ |
95 | } |
96 | ||
843267b1 | 97 | /* |
6f71a9f6 MK |
98 | * Uprintf prints to the current user's terminal. |
99 | * It may block if the tty queue is overfull. | |
ca9b16e5 MK |
100 | * No message is printed if the queue does not clear |
101 | * in a reasonable time. | |
6f71a9f6 MK |
102 | * Should determine whether current terminal user is related |
103 | * to this process. | |
843267b1 BJ |
104 | */ |
105 | /*VARARGS1*/ | |
106 | uprintf(fmt, x1) | |
b725a0ca | 107 | char *fmt; |
843267b1 | 108 | unsigned x1; |
96d38f03 | 109 | { |
c359fb80 | 110 | #ifdef notdef |
6f71a9f6 | 111 | register struct proc *p; |
c359fb80 | 112 | #endif |
6f71a9f6 | 113 | register struct tty *tp; |
96d38f03 | 114 | |
6f71a9f6 MK |
115 | if ((tp = u.u_ttyp) == NULL) |
116 | return; | |
117 | #ifdef notdef | |
118 | if (tp->t_pgrp && (p = pfind(tp->t_pgrp))) | |
c359fb80 | 119 | if (p->p_uid != u.u_uid) /* doesn't account for setuid */ |
6f71a9f6 MK |
120 | return; |
121 | #endif | |
ca9b16e5 MK |
122 | if (ttycheckoutq(tp, 1)) |
123 | prf(fmt, &x1, TOTTY, tp); | |
34ef3482 RC |
124 | } |
125 | ||
bd10af3f MK |
126 | /* |
127 | * tprintf prints on the specified terminal (console if none) | |
128 | * and logs the message. It is designed for error messages from | |
6f71a9f6 MK |
129 | * single-open devices, and may be called from interrupt level |
130 | * (does not sleep). | |
bd10af3f | 131 | */ |
34ef3482 | 132 | /*VARARGS2*/ |
6f71a9f6 MK |
133 | tprintf(tp, fmt, x1) |
134 | register struct tty *tp; | |
34ef3482 RC |
135 | char *fmt; |
136 | unsigned x1; | |
137 | { | |
6f71a9f6 | 138 | int flags = TOTTY | TOLOG; |
34ef3482 | 139 | |
6f71a9f6 | 140 | logpri(LOG_INFO); |
1d4b2ce4 MK |
141 | if (tp == (struct tty *)NULL) { |
142 | tp = constty; | |
143 | if (tp == (struct tty *)NULL) | |
144 | tp = &cons; | |
145 | } | |
6f71a9f6 MK |
146 | if (ttycheckoutq(tp, 0) == 0) |
147 | flags = TOLOG; | |
148 | prf(fmt, &x1, flags, tp); | |
149 | logwakeup(); | |
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); |
34ef3482 RC |
166 | prf(fmt, &x1, TOLOG, (struct tty *)0); |
167 | splx(s); | |
bd10af3f MK |
168 | if (!log_open) |
169 | prf(fmt, &x1, TOCONS, (struct tty *)0); | |
34ef3482 | 170 | logwakeup(); |
96d38f03 BJ |
171 | } |
172 | ||
6f71a9f6 MK |
173 | logpri(level) |
174 | int level; | |
175 | { | |
176 | ||
177 | putchar('<', TOLOG, (struct tty *)0); | |
8011f5df | 178 | printn((u_long)level, 10, TOLOG, (struct tty *)0); |
6f71a9f6 MK |
179 | putchar('>', TOLOG, (struct tty *)0); |
180 | } | |
181 | ||
c55a3dd0 MK |
182 | /*VARARGS1*/ |
183 | addlog(fmt, x1) | |
184 | char *fmt; | |
185 | unsigned x1; | |
186 | { | |
187 | register s = splhigh(); | |
188 | ||
189 | prf(fmt, &x1, TOLOG, (struct tty *)0); | |
190 | splx(s); | |
191 | if (!log_open) | |
192 | prf(fmt, &x1, TOCONS, (struct tty *)0); | |
193 | logwakeup(); | |
194 | } | |
195 | ||
34ef3482 | 196 | prf(fmt, adx, flags, ttyp) |
b725a0ca BJ |
197 | register char *fmt; |
198 | register u_int *adx; | |
34ef3482 | 199 | struct tty *ttyp; |
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; |
34ef3482 | 209 | putchar(c, flags, ttyp); |
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: | |
34ef3482 | 230 | printn((u_long)*adx, b, flags, ttyp); |
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) | |
34ef3482 | 237 | putchar(c, flags, ttyp); |
fb1db32c | 238 | #endif |
c55a3dd0 | 239 | #if BYTE_ORDER == BIG_ENDIAN |
fb1db32c MK |
240 | if (c = (b & 0x7f)) |
241 | putchar(c, flags, ttyp); | |
242 | #endif | |
843267b1 | 243 | break; |
3c79e4ff BJ |
244 | case 'b': |
245 | b = *adx++; | |
246 | s = (char *)*adx; | |
34ef3482 | 247 | printn((u_long)b, *s++, flags, ttyp); |
3c79e4ff BJ |
248 | any = 0; |
249 | if (b) { | |
3c79e4ff BJ |
250 | while (i = *s++) { |
251 | if (b & (1 << (i-1))) { | |
fb1db32c | 252 | putchar(any ? ',' : '<', flags, ttyp); |
3c79e4ff BJ |
253 | any = 1; |
254 | for (; (c = *s) > 32; s++) | |
34ef3482 | 255 | putchar(c, flags, ttyp); |
3c79e4ff BJ |
256 | } else |
257 | for (; *s > 32; s++) | |
258 | ; | |
259 | } | |
1ce587f2 | 260 | if (any) |
34ef3482 | 261 | putchar('>', flags, ttyp); |
3c79e4ff BJ |
262 | } |
263 | break; | |
264 | ||
843267b1 | 265 | case 's': |
8cbb423c | 266 | s = (char *)*adx; |
96d38f03 | 267 | while (c = *s++) |
34ef3482 | 268 | putchar(c, flags, ttyp); |
843267b1 | 269 | break; |
2bb8d359 | 270 | |
c55a3dd0 MK |
271 | case 'r': |
272 | s = (char *)*adx++; | |
6a79e262 | 273 | prf(s, (u_int *)*adx, flags, ttyp); |
c55a3dd0 MK |
274 | break; |
275 | ||
2bb8d359 | 276 | case '%': |
34ef3482 | 277 | putchar('%', flags, ttyp); |
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 | */ | |
34ef3482 | 288 | printn(n, b, flags, ttyp) |
a0eab615 | 289 | u_long n; |
34ef3482 | 290 | struct tty *ttyp; |
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) { | |
297 | putchar('-', flags, ttyp); | |
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 | |
34ef3482 | 308 | putchar(*--cp, flags, ttyp); |
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*/ |
8d907ccf | 356 | putchar(c, flags, tp) |
843267b1 | 357 | register int c; |
8d907ccf | 358 | struct tty *tp; |
96d38f03 | 359 | { |
c55a3dd0 | 360 | extern int msgbufmapped; |
96d38f03 | 361 | |
ed2d0915 MK |
362 | if (panicstr) |
363 | constty = 0; | |
364 | if ((flags & TOCONS) && tp == 0 && constty) { | |
365 | tp = constty; | |
366 | flags |= TOTTY; | |
367 | } | |
1d4b2ce4 MK |
368 | if ((flags & TOCONS) && panicstr == 0 && tp == 0 && constty) { |
369 | tp = constty; | |
370 | flags |= TOTTY; | |
371 | } | |
34ef3482 | 372 | if (flags & TOTTY) { |
6f71a9f6 MK |
373 | register s = spltty(); |
374 | ||
375 | if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == | |
376 | (TS_CARR_ON | TS_ISOPEN)) { | |
843267b1 | 377 | if (c == '\n') |
2752c877 BJ |
378 | (void) ttyoutput('\r', tp); |
379 | (void) ttyoutput(c, tp); | |
d11b28dc | 380 | ttstart(tp); |
1d4b2ce4 MK |
381 | flags &= ~TOCONS; |
382 | } else if ((flags & TOCONS) && tp == constty) | |
383 | constty = 0; | |
6f71a9f6 | 384 | splx(s); |
d11b28dc | 385 | } |
c55a3dd0 MK |
386 | if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && |
387 | msgbufmapped) { | |
90f8d91f | 388 | if (msgbuf.msg_magic != MSG_MAGIC) { |
76db4195 SL |
389 | register int i; |
390 | ||
90f8d91f | 391 | msgbuf.msg_magic = MSG_MAGIC; |
34ef3482 | 392 | msgbuf.msg_bufx = msgbuf.msg_bufr = 0; |
76db4195 SL |
393 | for (i=0; i < MSG_BSIZE; i++) |
394 | msgbuf.msg_bufc[i] = 0; | |
90f8d91f | 395 | } |
7e401e0e | 396 | msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; |
90f8d91f BJ |
397 | if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) |
398 | msgbuf.msg_bufx = 0; | |
96d38f03 | 399 | } |
1d4b2ce4 | 400 | (*v_console)(c); |
96d38f03 | 401 | } |