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