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