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