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