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