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