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