1 /* $NetBSD: subr_prf.c,v 1.40 1997/04/17 00:06:28 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1986, 1988, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/buf.h> 46 #include <sys/conf.h> 47 #include <sys/reboot.h> 48 #include <sys/msgbuf.h> 49 #include <sys/proc.h> 50 #include <sys/ioctl.h> 51 #include <sys/vnode.h> 52 #include <sys/file.h> 53 #include <sys/tty.h> 54 #include <sys/tprintf.h> 55 #include <sys/syslog.h> 56 #include <sys/malloc.h> 57 58 #include <dev/cons.h> 59 60 /* 61 * Note that stdarg.h and the ANSI style va_start macro is used for both 62 * ANSI and traditional C compilers. 63 * XXX: This requires that stdarg.h defines: va_alist, va_dcl 64 */ 65 #include <machine/stdarg.h> 66 67 #include "ipkdb.h" 68 69 #ifdef KADB 70 #include <machine/kdbparam.h> 71 #endif 72 #ifdef KGDB 73 #include <machine/cpu.h> 74 #endif 75 76 #define TOCONS 0x01 77 #define TOTTY 0x02 78 #define TOLOG 0x04 79 80 /* 81 * This is the size of the buffer that should be passed to ksnprintn(). 82 * It's the length of a long in base 8, plus NULL. 83 */ 84 #define KSNPRINTN_BUFSIZE (sizeof(long) * NBBY / 3 + 2) 85 86 struct tty *constty; /* pointer to console "window" tty */ 87 88 void (*v_putc) __P((int)) = cnputc; /* routine to putc on virtual console */ 89 90 static void putchar __P((int, int, struct tty *)); 91 static char *ksnprintn __P((u_long, int, int *, char *, size_t)); 92 void kprintf __P((const char *, int, struct tty *, va_list)); 93 94 int consintr = 1; /* Ok to handle console interrupts? */ 95 96 /* 97 * Variable panicstr contains argument to first call to panic; used as flag 98 * to indicate that the kernel has already called panic. 99 */ 100 const char *panicstr; 101 102 /* 103 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 104 * and then reboots. If we are called twice, then we avoid trying to sync 105 * the disks as this often leads to recursive panics. 106 */ 107 void 108 #ifdef __STDC__ 109 panic(const char *fmt, ...) 110 #else 111 panic(fmt, va_alist) 112 char *fmt; 113 va_dcl 114 #endif 115 { 116 int bootopt; 117 va_list ap; 118 119 bootopt = RB_AUTOBOOT | RB_DUMP; 120 if (panicstr) 121 bootopt |= RB_NOSYNC; 122 else 123 panicstr = fmt; 124 125 va_start(ap, fmt); 126 #ifdef __powerpc__ /* XXX */ 127 printf("panic: "); /* XXX */ 128 vprintf(fmt, ap); /* XXX */ 129 printf("\n"); /* XXX */ 130 #else /* XXX */ 131 printf("panic: %:\n", fmt, ap); /* XXX */ 132 #endif /* XXX */ 133 va_end(ap); 134 135 #if NIPKDB > 0 136 ipkdb_panic(); 137 #endif 138 #ifdef KGDB 139 kgdb_panic(); 140 #endif 141 #ifdef KADB 142 if (boothowto & RB_KDB) 143 kdbpanic(); 144 #endif 145 #ifdef DDB 146 if (db_onpanic) 147 Debugger(); 148 #endif 149 cpu_reboot(bootopt, NULL); 150 } 151 152 /* 153 * Warn that a system table is full. 154 */ 155 void 156 tablefull(tab) 157 const char *tab; 158 { 159 160 log(LOG_ERR, "%s: table is full\n", tab); 161 } 162 163 /* 164 * Uprintf prints to the controlling terminal for the current process. 165 * It may block if the tty queue is overfull. No message is printed if 166 * the queue does not clear in a reasonable time. 167 */ 168 void 169 #ifdef __STDC__ 170 uprintf(const char *fmt, ...) 171 #else 172 uprintf(fmt, va_alist) 173 char *fmt; 174 va_dcl 175 #endif 176 { 177 register struct proc *p = curproc; 178 va_list ap; 179 180 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 181 va_start(ap, fmt); 182 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 183 va_end(ap); 184 } 185 } 186 187 tpr_t 188 tprintf_open(p) 189 register struct proc *p; 190 { 191 192 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 193 SESSHOLD(p->p_session); 194 return ((tpr_t) p->p_session); 195 } 196 return ((tpr_t) NULL); 197 } 198 199 void 200 tprintf_close(sess) 201 tpr_t sess; 202 { 203 204 if (sess) 205 SESSRELE((struct session *) sess); 206 } 207 208 /* 209 * tprintf prints on the controlling terminal associated 210 * with the given session. 211 */ 212 void 213 #ifdef __STDC__ 214 tprintf(tpr_t tpr, const char *fmt, ...) 215 #else 216 tprintf(tpr, fmt, va_alist) 217 tpr_t tpr; 218 char *fmt; 219 va_dcl 220 #endif 221 { 222 register struct session *sess = (struct session *)tpr; 223 struct tty *tp = NULL; 224 int flags = TOLOG; 225 va_list ap; 226 227 logpri(LOG_INFO); 228 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 229 flags |= TOTTY; 230 tp = sess->s_ttyp; 231 } 232 va_start(ap, fmt); 233 kprintf(fmt, flags, tp, ap); 234 va_end(ap); 235 logwakeup(); 236 } 237 238 /* 239 * Ttyprintf displays a message on a tty; it should be used only by 240 * the tty driver, or anything that knows the underlying tty will not 241 * be revoke(2)'d away. Other callers should use tprintf. 242 */ 243 void 244 #ifdef __STDC__ 245 ttyprintf(struct tty *tp, const char *fmt, ...) 246 #else 247 ttyprintf(tp, fmt, va_alist) 248 struct tty *tp; 249 char *fmt; 250 va_dcl 251 #endif 252 { 253 va_list ap; 254 255 va_start(ap, fmt); 256 kprintf(fmt, TOTTY, tp, ap); 257 va_end(ap); 258 } 259 260 extern int log_open; 261 262 /* 263 * Log writes to the log buffer, and guarantees not to sleep (so can be 264 * called by interrupt routines). If there is no process reading the 265 * log yet, it writes to the console also. 266 */ 267 void 268 #ifdef __STDC__ 269 log(int level, const char *fmt, ...) 270 #else 271 log(level, fmt, va_alist) 272 int level; 273 char *fmt; 274 va_dcl 275 #endif 276 { 277 register int s; 278 va_list ap; 279 280 s = splhigh(); 281 logpri(level); 282 va_start(ap, fmt); 283 kprintf(fmt, TOLOG, NULL, ap); 284 splx(s); 285 va_end(ap); 286 if (!log_open) { 287 va_start(ap, fmt); 288 kprintf(fmt, TOCONS, NULL, ap); 289 va_end(ap); 290 } 291 logwakeup(); 292 } 293 294 void 295 logpri(level) 296 int level; 297 { 298 register int ch; 299 register char *p; 300 char snbuf[KSNPRINTN_BUFSIZE]; 301 302 putchar('<', TOLOG, NULL); 303 for (p = ksnprintn((u_long)level, 10, NULL, snbuf, sizeof(snbuf)); 304 (ch = *p--) != 0;) 305 putchar(ch, TOLOG, NULL); 306 putchar('>', TOLOG, NULL); 307 } 308 309 void 310 #ifdef __STDC__ 311 addlog(const char *fmt, ...) 312 #else 313 addlog(fmt, va_alist) 314 char *fmt; 315 va_dcl 316 #endif 317 { 318 register int s; 319 va_list ap; 320 321 s = splhigh(); 322 va_start(ap, fmt); 323 kprintf(fmt, TOLOG, NULL, ap); 324 splx(s); 325 va_end(ap); 326 if (!log_open) { 327 va_start(ap, fmt); 328 kprintf(fmt, TOCONS, NULL, ap); 329 va_end(ap); 330 } 331 logwakeup(); 332 } 333 334 void 335 #ifdef __STDC__ 336 printf(const char *fmt, ...) 337 #else 338 printf(fmt, va_alist) 339 char *fmt; 340 va_dcl 341 #endif 342 { 343 va_list ap; 344 register int savintr; 345 346 savintr = consintr; /* disable interrupts */ 347 consintr = 0; 348 va_start(ap, fmt); 349 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 350 va_end(ap); 351 if (!panicstr) 352 logwakeup(); 353 consintr = savintr; /* reenable interrupts */ 354 } 355 356 #ifdef __powerpc__ /* XXX XXX XXX */ 357 void 358 vprintf(fmt, ap) 359 const char *fmt; 360 va_list ap; 361 { 362 register int savintr; 363 364 savintr = consintr; /* disable interrupts */ 365 consintr = 0; 366 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 367 if (!panicstr) 368 logwakeup(); 369 consintr = savintr; /* reenable interrupts */ 370 } 371 #endif /* __powerpc__ */ /* XXX XXX XXX */ 372 373 /* 374 * Scaled down version of printf(3). 375 * 376 * Two additional formats: 377 * 378 * The format %b is supported to decode error registers. 379 * Its usage is: 380 * 381 * printf("reg=%b\n", regval, "<base><arg>*"); 382 * 383 * where <base> is the output base expressed as a control character, e.g. 384 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 385 * the first of which gives the bit number to be inspected (origin 1), and 386 * the next characters (up to a control character, i.e. a character <= 32), 387 * give the name of the register. Thus: 388 * 389 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 390 * 391 * would produce output: 392 * 393 * reg=3<BITTWO,BITONE> 394 * 395 * The format %: passes an additional format string and argument list 396 * recursively. Its usage is: 397 * 398 * fn(char *fmt, ...) 399 * { 400 * va_list ap; 401 * va_start(ap, fmt); 402 * printf("prefix: %: suffix\n", fmt, ap); 403 * va_end(ap); 404 * } 405 * 406 * Space or zero padding and a field width are supported for the numeric 407 * formats only. 408 */ 409 void 410 kprintf(fmt, flags, tp, ap) 411 register const char *fmt; 412 int flags; 413 struct tty *tp; 414 va_list ap; 415 { 416 register char *p, *q; 417 register int ch, n; 418 u_long ul; 419 int base, lflag, tmp, width; 420 char padc, snbuf[KSNPRINTN_BUFSIZE]; 421 422 for (;;) { 423 padc = ' '; 424 width = 0; 425 while ((ch = *(const u_char *)fmt++) != '%') { 426 if (ch == '\0') 427 return; 428 putchar(ch, flags, tp); 429 } 430 lflag = 0; 431 reswitch: switch (ch = *(const u_char *)fmt++) { 432 case '0': 433 case '.': 434 padc = '0'; 435 goto reswitch; 436 case '1': case '2': case '3': case '4': 437 case '5': case '6': case '7': case '8': case '9': 438 for (width = 0;; ++fmt) { 439 width = width * 10 + ch - '0'; 440 ch = *fmt; 441 if (ch < '0' || ch > '9') 442 break; 443 } 444 goto reswitch; 445 case 'l': 446 lflag = 1; 447 goto reswitch; 448 case 'b': 449 ul = va_arg(ap, int); 450 p = va_arg(ap, char *); 451 for (q = ksnprintn(ul, *p++, NULL, snbuf, 452 sizeof(snbuf)); (ch = *q--) != 0;) 453 putchar(ch, flags, tp); 454 455 if (!ul) 456 break; 457 458 for (tmp = 0; (n = *p++) != 0;) { 459 if (ul & (1 << (n - 1))) { 460 putchar(tmp ? ',' : '<', flags, tp); 461 for (; (n = *p) > ' '; ++p) 462 putchar(n, flags, tp); 463 tmp = 1; 464 } else 465 for (; *p > ' '; ++p) 466 continue; 467 } 468 if (tmp) 469 putchar('>', flags, tp); 470 break; 471 case 'c': 472 putchar(va_arg(ap, int), flags, tp); 473 break; 474 #ifndef __powerpc__ /* XXX XXX XXX */ 475 case ':': 476 p = va_arg(ap, char *); 477 kprintf(p, flags, tp, va_arg(ap, va_list)); 478 break; 479 #endif /* __powerpc__ */ /* XXX XXX XXX */ 480 case 's': 481 if ((p = va_arg(ap, char *)) == NULL) 482 p = "(null)"; 483 while ((ch = *p++) != 0) 484 putchar(ch, flags, tp); 485 break; 486 case 'd': 487 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 488 if ((long)ul < 0) { 489 putchar('-', flags, tp); 490 ul = -(long)ul; 491 } 492 base = 10; 493 goto number; 494 case 'o': 495 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 496 base = 8; 497 goto number; 498 case 'u': 499 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 500 base = 10; 501 goto number; 502 case 'p': 503 putchar('0', flags, tp); 504 putchar('x', flags, tp); 505 ul = (u_long)va_arg(ap, void *); 506 base = 16; 507 goto number; 508 case 'x': 509 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 510 base = 16; 511 number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf)); 512 if (width && (width -= tmp) > 0) 513 while (width--) 514 putchar(padc, flags, tp); 515 while ((ch = *p--) != 0) 516 putchar(ch, flags, tp); 517 break; 518 default: 519 putchar('%', flags, tp); 520 if (lflag) 521 putchar('l', flags, tp); 522 /* FALLTHROUGH */ 523 case '%': 524 putchar(ch, flags, tp); 525 } 526 } 527 } 528 529 /* 530 * Print a character on console or users terminal. If destination is 531 * the console then the last MSGBUFS characters are saved in msgbuf for 532 * inspection later. 533 */ 534 static void 535 putchar(c, flags, tp) 536 register int c; 537 int flags; 538 struct tty *tp; 539 { 540 extern int msgbufmapped; 541 register struct msgbuf *mbp; 542 543 if (panicstr) 544 constty = NULL; 545 if ((flags & TOCONS) && tp == NULL && constty) { 546 tp = constty; 547 flags |= TOTTY; 548 } 549 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 550 (flags & TOCONS) && tp == constty) 551 constty = NULL; 552 if ((flags & TOLOG) && 553 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 554 mbp = msgbufp; 555 if (mbp->msg_magic != MSG_MAGIC) { 556 bzero((caddr_t)mbp, sizeof(*mbp)); 557 mbp->msg_magic = MSG_MAGIC; 558 } 559 mbp->msg_bufc[mbp->msg_bufx++] = c; 560 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 561 mbp->msg_bufx = 0; 562 } 563 if ((flags & TOCONS) && constty == NULL && c != '\0') 564 (*v_putc)(c); 565 } 566 567 /* 568 * Scaled down version of sprintf(3). 569 */ 570 int 571 #ifdef __STDC__ 572 sprintf(char *buf, const char *cfmt, ...) 573 #else 574 sprintf(buf, cfmt, va_alist) 575 char *buf; 576 const char *cfmt; 577 va_dcl 578 #endif 579 { 580 register const char *fmt = cfmt; 581 register char *p, *bp; 582 register int ch, base; 583 u_long ul; 584 int lflag, tmp, width; 585 va_list ap; 586 char padc, snbuf[KSNPRINTN_BUFSIZE]; 587 588 va_start(ap, cfmt); 589 for (bp = buf; ; ) { 590 padc = ' '; 591 width = 0; 592 while ((ch = *(const u_char *)fmt++) != '%') 593 if ((*bp++ = ch) == '\0') 594 return ((bp - buf) - 1); 595 596 lflag = 0; 597 reswitch: switch (ch = *(const u_char *)fmt++) { 598 case '0': 599 padc = '0'; 600 goto reswitch; 601 case '1': case '2': case '3': case '4': 602 case '5': case '6': case '7': case '8': case '9': 603 for (width = 0;; ++fmt) { 604 width = width * 10 + ch - '0'; 605 ch = *fmt; 606 if (ch < '0' || ch > '9') 607 break; 608 } 609 goto reswitch; 610 case 'l': 611 lflag = 1; 612 goto reswitch; 613 /* case 'b': ... break; XXX */ 614 case 'c': 615 *bp++ = va_arg(ap, int); 616 break; 617 /* case 'r': ... break; XXX */ 618 case 's': 619 p = va_arg(ap, char *); 620 while ((*bp++ = *p++) != 0) 621 continue; 622 --bp; 623 break; 624 case 'd': 625 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 626 if ((long)ul < 0) { 627 *bp++ = '-'; 628 ul = -(long)ul; 629 } 630 base = 10; 631 goto number; 632 break; 633 case 'o': 634 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 635 base = 8; 636 goto number; 637 break; 638 case 'u': 639 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 640 base = 10; 641 goto number; 642 break; 643 case 'p': 644 *bp++ = '0'; 645 *bp++ = 'x'; 646 ul = (u_long)va_arg(ap, void *); 647 base = 16; 648 goto number; 649 case 'x': 650 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 651 base = 16; 652 number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf)); 653 if (width && (width -= tmp) > 0) 654 while (width--) 655 *bp++ = padc; 656 while ((ch = *p--) != 0) 657 *bp++ = ch; 658 break; 659 default: 660 *bp++ = '%'; 661 if (lflag) 662 *bp++ = 'l'; 663 /* FALLTHROUGH */ 664 case '%': 665 *bp++ = ch; 666 } 667 } 668 va_end(ap); 669 } 670 671 /* 672 * Put a number (base <= 16) in a buffer in reverse order; return an 673 * optional length and a pointer to the NULL terminated (preceded?) 674 * buffer. 675 */ 676 static char * 677 ksnprintn(ul, base, lenp, buf, buflen) 678 register u_long ul; 679 register int base, *lenp; 680 char *buf; 681 size_t buflen; 682 { 683 register char *p; 684 685 p = buf; 686 *p = '\0'; /* ensure NULL `termination' */ 687 688 /* 689 * Don't even bother of the buffer's not big enough. No 690 * value at all is better than a wrong value, and we 691 * have a lot of control over the buffer that's passed 692 * to this function, since it's not exported. 693 */ 694 if (buflen < KSNPRINTN_BUFSIZE) 695 return (p); 696 697 do { 698 *++p = "0123456789abcdef"[ul % base]; 699 } while (ul /= base); 700 if (lenp) 701 *lenp = p - buf; 702 return (p); 703 } 704 705 /* 706 * Print a bitmask into the provided buffer, and return a pointer 707 * to that buffer. 708 */ 709 char * 710 bitmask_snprintf(ul, p, buf, buflen) 711 u_long ul; 712 const char *p; 713 char *buf; 714 size_t buflen; 715 { 716 char *bp, *q; 717 size_t left; 718 register int n; 719 int ch, tmp; 720 char snbuf[KSNPRINTN_BUFSIZE]; 721 722 bp = buf; 723 bzero(buf, buflen); 724 725 /* 726 * Always leave room for the trailing NULL. 727 */ 728 left = buflen - 1; 729 730 /* 731 * Print the value into the buffer. Abort if there's not 732 * enough room. 733 */ 734 if (buflen < KSNPRINTN_BUFSIZE) 735 return (buf); 736 737 for (q = ksnprintn(ul, *p++, NULL, snbuf, sizeof(snbuf)); 738 (ch = *q--) != 0;) { 739 *bp++ = ch; 740 left--; 741 } 742 743 /* 744 * If the value we printed was 0, or if we don't have room for 745 * "<x>", we're done. 746 */ 747 if (ul == 0 || left < 3) 748 return (buf); 749 750 #define PUTBYTE(b, c, l) \ 751 *(b)++ = (c); \ 752 if (--(l) == 0) \ 753 goto out; 754 755 for (tmp = 0; (n = *p++) != 0;) { 756 if (ul & (1 << (n - 1))) { 757 PUTBYTE(bp, tmp ? ',' : '<', left); 758 for (; (n = *p) > ' '; ++p) { 759 PUTBYTE(bp, n, left); 760 } 761 tmp = 1; 762 } else 763 for (; *p > ' '; ++p) 764 continue; 765 } 766 if (tmp) 767 *bp = '>'; 768 769 #undef PUTBYTE 770 771 out: 772 return (buf); 773 } 774