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