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