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