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