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