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