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.38 (Berkeley) 03/11/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 continue; 385 } 386 if (tmp) 387 putchar('>', flags, tp); 388 break; 389 case 'c': 390 putchar(va_arg(ap, int), flags, tp); 391 break; 392 case 'r': 393 p = va_arg(ap, char *); 394 kprintf(p, flags, tp, va_arg(ap, va_list)); 395 break; 396 case 's': 397 p = va_arg(ap, char *); 398 while (ch = *p++) 399 putchar(ch, flags, tp); 400 break; 401 case 'd': 402 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 403 if ((long)ul < 0) { 404 putchar('-', flags, tp); 405 ul = -(long)ul; 406 } 407 base = 10; 408 goto number; 409 case 'o': 410 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 411 base = 8; 412 goto number; 413 case 'u': 414 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 415 base = 10; 416 goto number; 417 case 'x': 418 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 419 base = 16; 420 number: p = ksprintn(ul, base, &tmp); 421 if (width && (width -= tmp) > 0) 422 while (width--) 423 putchar(padc, flags, tp); 424 while (ch = *p--) 425 putchar(ch, flags, tp); 426 break; 427 default: 428 putchar('%', flags, tp); 429 if (lflag) 430 putchar('l', flags, tp); 431 /* FALLTHROUGH */ 432 case '%': 433 putchar(ch, flags, tp); 434 } 435 } 436 } 437 438 /* 439 * Print a character on console or users terminal. If destination is 440 * the console then the last MSGBUFS characters are saved in msgbuf for 441 * inspection later. 442 */ 443 static void 444 putchar(c, flags, tp) 445 register int c; 446 int flags; 447 struct tty *tp; 448 { 449 extern int msgbufmapped; 450 register struct msgbuf *mbp; 451 452 if (panicstr) 453 constty = NULL; 454 if ((flags & TOCONS) && tp == NULL && constty) { 455 tp = constty; 456 flags |= TOTTY; 457 } 458 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 459 (flags & TOCONS) && tp == constty) 460 constty = NULL; 461 if ((flags & TOLOG) && 462 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 463 mbp = msgbufp; 464 if (mbp->msg_magic != MSG_MAGIC) { 465 bzero((caddr_t)mbp, sizeof(*mbp)); 466 mbp->msg_magic = MSG_MAGIC; 467 } 468 mbp->msg_bufc[mbp->msg_bufx++] = c; 469 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 470 mbp->msg_bufx = 0; 471 } 472 if ((flags & TOCONS) && constty == NULL && c != '\0') 473 (*v_putc)(c); 474 } 475 476 /* 477 * Scaled down version of sprintf(3). 478 */ 479 #ifdef __STDC__ 480 sprintf(char *buf, const char *cfmt, ...) 481 #else 482 sprintf(buf, cfmt, va_alist) 483 char *buf, *cfmt; 484 #endif 485 { 486 register const char *fmt = cfmt; 487 register char *p, *bp; 488 register int ch, base; 489 u_long ul; 490 int lflag; 491 va_list ap; 492 493 va_start(ap, cfmt); 494 for (bp = buf; ; ) { 495 while ((ch = *(u_char *)fmt++) != '%') 496 if ((*bp++ = ch) == '\0') 497 return ((bp - buf) - 1); 498 499 lflag = 0; 500 reswitch: switch (ch = *(u_char *)fmt++) { 501 case 'l': 502 lflag = 1; 503 goto reswitch; 504 case 'c': 505 *bp++ = va_arg(ap, int); 506 break; 507 case 's': 508 p = va_arg(ap, char *); 509 while (*bp++ = *p++) 510 continue; 511 --bp; 512 break; 513 case 'd': 514 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 515 if ((long)ul < 0) { 516 *bp++ = '-'; 517 ul = -(long)ul; 518 } 519 base = 10; 520 goto number; 521 break; 522 case 'o': 523 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 524 base = 8; 525 goto number; 526 break; 527 case 'u': 528 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 529 base = 10; 530 goto number; 531 break; 532 case 'x': 533 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 534 base = 16; 535 number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 536 *bp++ = ch; 537 break; 538 default: 539 *bp++ = '%'; 540 if (lflag) 541 *bp++ = 'l'; 542 /* FALLTHROUGH */ 543 case '%': 544 *bp++ = ch; 545 } 546 } 547 va_end(ap); 548 } 549 550 /* 551 * Put a number (base <= 16) in a buffer in reverse order; return an 552 * optional length and a pointer to the NULL terminated (preceded?) 553 * buffer. 554 */ 555 static char * 556 ksprintn(ul, base, lenp) 557 register u_long ul; 558 register int base, *lenp; 559 { /* A long in base 8, plus NULL. */ 560 static char buf[sizeof(long) * NBBY / 3 + 2]; 561 register char *p; 562 563 p = buf; 564 do { 565 *++p = "0123456789abcdef"[ul % base]; 566 } while (ul /= base); 567 if (lenp) 568 *lenp = p - buf; 569 return (p); 570 } 571