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