1 /*- 2 * Copyright (c) 1986, 1988, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)subr_prf.c 7.26 (Berkeley) 05/28/91 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "reboot.h" 15 #include "msgbuf.h" 16 #include "proc.h" 17 #include "ioctl.h" 18 #include "vnode.h" 19 #include "file.h" 20 #include "tty.h" 21 #include "tprintf.h" 22 #include "syslog.h" 23 #include "malloc.h" 24 25 /* 26 * Note that stdarg.h and the ANSI style va_start macro is used for both 27 * ANSI and traditional C compilers. 28 */ 29 #include <machine/stdarg.h> 30 31 #ifdef KADB 32 #include "machine/kdbparam.h" 33 #endif 34 35 #define TOCONS 0x01 36 #define TOTTY 0x02 37 #define TOLOG 0x04 38 39 struct tty *constty; /* pointer to console "window" tty */ 40 41 #ifdef KADB 42 extern cngetc(); /* standard console getc */ 43 int (*v_getc)() = cngetc; /* "" getc from virtual console */ 44 extern cnpoll(); 45 int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */ 46 #endif 47 extern cnputc(); /* standard console putc */ 48 int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 49 50 static void logpri __P((int level)); 51 static void putchar __P((int ch, int flags, struct tty *tp)); 52 static void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list)); 53 static char *ksprintn __P((u_long num, int base, int *len)); 54 55 /* 56 * Variable panicstr contains argument to first call to panic; used 57 * as flag to indicate that the kernel has already called panic. 58 */ 59 char *panicstr; 60 61 /* 62 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 63 * and then reboots. If we are called twice, then we avoid trying to sync 64 * the disks as this often leads to recursive panics. 65 */ 66 void 67 panic(msg) 68 char *msg; 69 { 70 int bootopt = RB_AUTOBOOT | RB_DUMP; 71 int s; 72 73 if (panicstr) 74 bootopt |= RB_NOSYNC; 75 else 76 panicstr = msg; 77 printf("panic: %s\n", msg); 78 #ifdef KGDB 79 kgdb_panic(); 80 #endif 81 #ifdef KADB 82 if (boothowto & RB_KDB) { 83 s = splnet(); /* below kdb pri */ 84 setsoftkdb(); 85 splx(s); 86 } 87 #endif 88 boot(bootopt); 89 } 90 91 /* 92 * Warn that a system table is full. 93 */ 94 void 95 tablefull(tab) 96 char *tab; 97 { 98 99 log(LOG_ERR, "%s: table is full\n", tab); 100 } 101 102 /* 103 * Uprintf prints to the controlling terminal for the current process. 104 * It may block if the tty queue is overfull. No message is printed if 105 * the queue does not clear in a reasonable time. 106 */ 107 void 108 #ifdef __STDC__ 109 uprintf(const char *fmt, ...) 110 #else 111 uprintf(fmt /*, va_alist */) 112 char *fmt; 113 #endif 114 { 115 register struct proc *p = curproc; 116 va_list ap; 117 118 va_start(ap, fmt); 119 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) 120 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 121 va_end(ap); 122 } 123 124 tpr_t 125 tprintf_open(p) 126 register struct proc *p; 127 { 128 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 129 SESSHOLD(p->p_session); 130 return ((tpr_t) p->p_session); 131 } 132 return ((tpr_t) NULL); 133 } 134 135 void 136 tprintf_close(sess) 137 tpr_t sess; 138 { 139 if (sess) 140 SESSRELE((struct session *) sess); 141 } 142 143 /* 144 * tprintf prints on the controlling terminal associated 145 * with the given session. 146 */ 147 void 148 #ifdef __STDC__ 149 tprintf(tpr_t tpr, const char *fmt, ...) 150 #else 151 tprintf(tpr, fmt /*, va_alist */) 152 tpr_t tpr; 153 char *fmt; 154 #endif 155 { 156 register struct session *sess = (struct session *)tpr; 157 struct tty *tp = NULL; 158 int flags = TOLOG; 159 va_list ap; 160 161 logpri(LOG_INFO); 162 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 163 flags |= TOTTY; 164 tp = sess->s_ttyp; 165 } 166 va_start(ap, fmt); 167 kprintf(fmt, flags, tp, ap); 168 va_end(ap); 169 logwakeup(); 170 } 171 172 /* 173 * Ttyprintf displays a message on a tty; it should be used only by 174 * the tty driver, or anything that knows the underlying tty will not 175 * be revoke(2)'d away. Other callers should use tprintf. 176 */ 177 void 178 #ifdef __STDC__ 179 ttyprintf(struct tty *tp, const char *fmt, ...) 180 #else 181 ttyprintf(tp, fmt /*, va_alist */) 182 struct tty *tp; 183 char *fmt; 184 #endif 185 { 186 va_list ap; 187 188 va_start(ap, fmt); 189 kprintf(fmt, TOTTY, tp, ap); 190 va_end(ap); 191 } 192 193 extern int log_open; 194 195 /* 196 * Log writes to the log buffer, and guarantees not to sleep (so can be 197 * called by interrupt routines). If there is no process reading the 198 * log yet, it writes to the console also. 199 */ 200 void 201 #ifdef __STDC__ 202 log(int level, const char *fmt, ...) 203 #else 204 log(level, fmt /*, va_alist */) 205 int level; 206 char *fmt; 207 #endif 208 { 209 register s = splhigh(); 210 va_list ap; 211 212 logpri(level); 213 va_start(ap, fmt); 214 kprintf(fmt, TOLOG, NULL, ap); 215 splx(s); 216 if (!log_open) 217 kprintf(fmt, TOCONS, NULL, ap); 218 va_end(ap); 219 logwakeup(); 220 } 221 222 static void 223 logpri(level) 224 int level; 225 { 226 register int ch; 227 register char *p; 228 229 putchar('<', TOLOG, NULL); 230 for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 231 putchar(ch, TOLOG, NULL); 232 putchar('>', TOLOG, NULL); 233 } 234 235 void 236 #ifdef __STDC__ 237 addlog(const char *fmt, ...) 238 #else 239 addlog(fmt /*, va_alist */) 240 char *fmt; 241 #endif 242 { 243 register s = splhigh(); 244 va_list ap; 245 246 va_start(ap, fmt); 247 kprintf(fmt, TOLOG, NULL, ap); 248 splx(s); 249 if (!log_open) 250 kprintf(fmt, TOCONS, NULL, ap); 251 va_end(ap); 252 logwakeup(); 253 } 254 255 int consintr = 1; /* ok to handle console interrupts? */ 256 257 void 258 #ifdef __STDC__ 259 printf(const char *fmt, ...) 260 #else 261 printf(fmt /*, va_alist */) 262 char *fmt; 263 #endif 264 { 265 register int savintr; 266 va_list ap; 267 268 savintr = consintr; /* disable interrupts */ 269 consintr = 0; 270 va_start(ap, fmt); 271 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 272 va_end(ap); 273 if (!panicstr) 274 logwakeup(); 275 consintr = savintr; /* reenable interrupts */ 276 } 277 278 /* 279 * Scaled down version of printf(3). 280 * 281 * Two additional formats: 282 * 283 * The format %b is supported to decode error registers. 284 * Its usage is: 285 * 286 * printf("reg=%b\n", regval, "<base><arg>*"); 287 * 288 * where <base> is the output base expressed as a control character, e.g. 289 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 290 * the first of which gives the bit number to be inspected (origin 1), and 291 * the next characters (up to a control character, i.e. a character <= 32), 292 * give the name of the register. Thus: 293 * 294 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 295 * 296 * would produce output: 297 * 298 * reg=3<BITTWO,BITONE> 299 * 300 * The format %r is supposed to pass an additional format string and argument 301 * list recursively. 302 * Its usage is: 303 * 304 * fn(otherstuff, fmt [, arg1, ... ]) 305 * char *fmt; 306 * u_int arg1, ...; 307 * 308 * printf("prefix: %r, other stuff\n", fmt, ap); 309 * 310 * Space or zero padding and a field width are supported for the numeric 311 * formats only. 312 */ 313 static void 314 kprintf(fmt, flags, tp, ap) 315 register const char *fmt; 316 int flags; 317 struct tty *tp; 318 va_list ap; 319 { 320 register char *p; 321 register int ch, n; 322 u_long ul; 323 int base, lflag, tmp, width; 324 char padc; 325 326 for (;;) { 327 padc = ' '; 328 width = 0; 329 while ((ch = *fmt++) != '%') { 330 if (ch == '\0') 331 return; 332 putchar(ch, flags, tp); 333 } 334 lflag = 0; 335 reswitch: switch (ch = *fmt++) { 336 case '0': 337 padc = '0'; 338 goto reswitch; 339 case '1': case '2': case '3': case '4': 340 case '5': case '6': case '7': case '8': case '9': 341 for (width = 0;; ++fmt) { 342 width = width * 10 + ch - '0'; 343 ch = *fmt; 344 if (ch < '0' || ch > '9') 345 break; 346 } 347 goto reswitch; 348 case 'l': 349 lflag = 1; 350 goto reswitch; 351 case 'b': 352 ul = va_arg(ap, int); 353 p = va_arg(ap, char *); 354 for (p = ksprintn(ul, *p++, NULL); ch = *p--;) 355 putchar(ch, flags, tp); 356 357 if (!ul) 358 break; 359 360 for (tmp = 0; n = *p++;) { 361 if (ul & (1 << (n - 1))) { 362 putchar(tmp ? ',' : '<', flags, tp); 363 for (; (n = *p) > ' '; ++p) 364 putchar(n, flags, tp); 365 tmp = 1; 366 } else 367 for (; *p > ' '; ++p); 368 } 369 if (tmp) 370 putchar('>', flags, tp); 371 break; 372 case 'c': 373 putchar(va_arg(ap, int), flags, tp); 374 break; 375 case 'r': 376 p = va_arg(ap, char *); 377 kprintf(p, flags, tp, va_arg(ap, va_list)); 378 break; 379 case 's': 380 p = va_arg(ap, char *); 381 while (ch = *p++) 382 putchar(ch, flags, tp); 383 break; 384 case 'd': 385 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 386 if ((long)ul < 0) { 387 putchar('-', flags, tp); 388 ul = -(long)ul; 389 } 390 base = 10; 391 goto number; 392 case 'o': 393 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 394 base = 8; 395 goto number;; 396 case 'u': 397 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 398 base = 10; 399 goto number; 400 case 'x': 401 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 402 base = 16; 403 number: p = ksprintn(ul, base, &tmp); 404 if (width && (width -= tmp) > 0) 405 while (width--) 406 putchar(padc, flags, tp); 407 while (ch = *p--) 408 putchar(ch, flags, tp); 409 break; 410 default: 411 putchar('%', flags, tp); 412 if (lflag) 413 putchar('l', flags, tp); 414 /* FALLTHROUGH */ 415 case '%': 416 putchar(ch, flags, tp); 417 } 418 } 419 } 420 421 /* 422 * Print a character on console or users terminal. If destination is 423 * the console then the last MSGBUFS characters are saved in msgbuf for 424 * inspection later. 425 */ 426 static void 427 putchar(c, flags, tp) 428 register int c; 429 int flags; 430 struct tty *tp; 431 { 432 extern int msgbufmapped; 433 register struct msgbuf *mbp; 434 435 if (panicstr) 436 constty = NULL; 437 if ((flags & TOCONS) && tp == NULL && constty) { 438 tp = constty; 439 flags |= TOTTY; 440 } 441 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 442 (flags & TOCONS) && tp == constty) 443 constty = NULL; 444 if ((flags & TOLOG) && 445 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 446 mbp = msgbufp; 447 if (mbp->msg_magic != MSG_MAGIC) { 448 register int i; 449 450 mbp->msg_magic = MSG_MAGIC; 451 mbp->msg_bufx = mbp->msg_bufr = 0; 452 for (i = 0; i < MSG_BSIZE; i++) 453 mbp->msg_bufc[i] = 0; 454 } 455 mbp->msg_bufc[mbp->msg_bufx++] = c; 456 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 457 mbp->msg_bufx = 0; 458 } 459 if ((flags & TOCONS) && constty == NULL && c != '\0') 460 (*v_putc)(c); 461 } 462 463 /* 464 * Scaled down version of sprintf(3). 465 */ 466 #ifdef __STDC__ 467 sprintf(char *buf, const char *fmt, ...) 468 #else 469 sprintf(buf, fmt /*, va_alist */) 470 char *buf, *fmt; 471 #endif 472 { 473 register char *p, *bp; 474 register int ch, base; 475 u_long ul; 476 int lflag; 477 va_list ap; 478 479 va_start(ap, fmt); 480 for (bp = buf;;) { 481 while ((ch = *fmt++) != '%') 482 if ((*bp++ = ch) == '\0') 483 return((bp - buf) - 1); 484 lflag = 0; 485 reswitch: switch (ch = *fmt++) { 486 case 'l': 487 lflag = 1; 488 goto reswitch; 489 case 'c': 490 *bp++ = va_arg(ap, int); 491 break; 492 case 's': 493 p = va_arg(ap, char *); 494 while (*bp++ = *p++); 495 --bp; 496 break; 497 case 'd': 498 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 499 if ((long)ul < 0) { 500 *bp++ = '-'; 501 ul = -(long)ul; 502 } 503 base = 10; 504 goto number; 505 break; 506 case 'o': 507 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 508 base = 8; 509 goto number; 510 break; 511 case 'u': 512 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 513 base = 10; 514 goto number; 515 break; 516 case 'x': 517 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 518 base = 16; 519 number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 520 *bp++ = ch; 521 break; 522 default: 523 *bp++ = '%'; 524 if (lflag) 525 *bp++ = 'l'; 526 /* FALLTHROUGH */ 527 case '%': 528 *bp++ = ch; 529 } 530 } 531 va_end(ap); 532 } 533 534 /* 535 * Put a number (base <= 16) in a buffer in reverse order; return an 536 * optional length and a pointer to the NULL terminated (preceded?) 537 * buffer. 538 */ 539 static char * 540 ksprintn(ul, base, lenp) 541 register u_long ul; 542 register int base, *lenp; 543 { /* A long in base 8, plus NULL. */ 544 static char buf[sizeof(long) * NBBY / 3 + 2]; 545 register char *p; 546 547 p = buf; 548 do { 549 *++p = "0123456789abcdef"[ul % base]; 550 } while (ul /= base); 551 if (lenp) 552 *lenp = p - buf; 553 return(p); 554 } 555