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 * $FreeBSD: src/sys/kern/subr_prf.c,v 1.61.2.5 2002/08/31 18:22:08 dwmalone Exp $ 40 * $DragonFly: src/sys/kern/subr_prf.c,v 1.9 2005/09/29 20:43:56 dillon Exp $ 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/msgbuf.h> 47 #include <sys/malloc.h> 48 #include <sys/proc.h> 49 #include <sys/tty.h> 50 #include <sys/tprintf.h> 51 #include <sys/syslog.h> 52 #include <sys/cons.h> 53 #include <sys/uio.h> 54 #include <sys/sysctl.h> 55 #include <sys/lock.h> 56 57 /* 58 * Note that stdarg.h and the ANSI style va_start macro is used for both 59 * ANSI and traditional C compilers. We use the __ machine version to stay 60 * within the kernel header file set. 61 */ 62 #include <machine/stdarg.h> 63 64 #define TOCONS 0x01 65 #define TOTTY 0x02 66 #define TOLOG 0x04 67 68 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 69 #define MAXNBUF (sizeof(quad_t) * NBBY + 1) 70 71 struct putchar_arg { 72 int flags; 73 int pri; 74 struct tty *tty; 75 }; 76 77 struct snprintf_arg { 78 char *str; 79 size_t remain; 80 }; 81 82 extern int log_open; 83 84 struct tty *constty; /* pointer to console "window" tty */ 85 86 static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 87 static void msglogchar(int c, int pri); 88 static void msgaddchar(int c, void *dummy); 89 static void putchar (int ch, void *arg); 90 static char *ksprintn (char *nbuf, u_long num, int base, int *len); 91 static char *ksprintqn (char *nbuf, u_quad_t num, int base, int *len); 92 static void snprintf_func (int ch, void *arg); 93 94 static int consintr = 1; /* Ok to handle console interrupts? */ 95 static int msgbufmapped; /* Set when safe to use msgbuf */ 96 int msgbuftrigger; 97 98 static int log_console_output = 1; 99 TUNABLE_INT("kern.log_console_output", &log_console_output); 100 SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW, 101 &log_console_output, 0, ""); 102 103 static int unprivileged_read_msgbuf = 1; 104 SYSCTL_INT(_kern, OID_AUTO, unprivileged_read_msgbuf, CTLFLAG_RW, 105 &unprivileged_read_msgbuf, 0, 106 "Unprivileged processes may read the kernel message buffer"); 107 108 /* 109 * Warn that a system table is full. 110 */ 111 void 112 tablefull(const char *tab) 113 { 114 115 log(LOG_ERR, "%s: table is full\n", tab); 116 } 117 118 /* 119 * Uprintf prints to the controlling terminal for the current process. 120 * It may block if the tty queue is overfull. No message is printed if 121 * the queue does not clear in a reasonable time. 122 */ 123 int 124 uprintf(const char *fmt, ...) 125 { 126 struct proc *p = curproc; 127 __va_list ap; 128 struct putchar_arg pca; 129 int retval = 0; 130 131 if (p && p->p_flag & P_CONTROLT && 132 p->p_session->s_ttyvp) { 133 __va_start(ap, fmt); 134 pca.tty = p->p_session->s_ttyp; 135 pca.flags = TOTTY; 136 137 retval = kvprintf(fmt, putchar, &pca, 10, ap); 138 __va_end(ap); 139 } 140 return retval; 141 } 142 143 tpr_t 144 tprintf_open(struct proc *p) 145 { 146 147 if ((p->p_flag & P_CONTROLT) && p->p_session->s_ttyvp) { 148 sess_hold(p->p_session); 149 return ((tpr_t) p->p_session); 150 } 151 return ((tpr_t) NULL); 152 } 153 154 void 155 tprintf_close(tpr_t sess) 156 { 157 if (sess) 158 sess_rele((struct session *) sess); 159 } 160 161 /* 162 * tprintf prints on the controlling terminal associated 163 * with the given session. 164 */ 165 int 166 tprintf(tpr_t tpr, const char *fmt, ...) 167 { 168 struct session *sess = (struct session *)tpr; 169 struct tty *tp = NULL; 170 int flags = TOLOG; 171 __va_list ap; 172 struct putchar_arg pca; 173 int retval; 174 175 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 176 flags |= TOTTY; 177 tp = sess->s_ttyp; 178 } 179 __va_start(ap, fmt); 180 pca.tty = tp; 181 pca.flags = flags; 182 pca.pri = LOG_INFO; 183 retval = kvprintf(fmt, putchar, &pca, 10, ap); 184 __va_end(ap); 185 msgbuftrigger = 1; 186 return retval; 187 } 188 189 /* 190 * Ttyprintf displays a message on a tty; it should be used only by 191 * the tty driver, or anything that knows the underlying tty will not 192 * be revoke(2)'d away. Other callers should use tprintf. 193 */ 194 int 195 ttyprintf(struct tty *tp, const char *fmt, ...) 196 { 197 __va_list ap; 198 struct putchar_arg pca; 199 int retval; 200 201 __va_start(ap, fmt); 202 pca.tty = tp; 203 pca.flags = TOTTY; 204 retval = kvprintf(fmt, putchar, &pca, 10, ap); 205 __va_end(ap); 206 return retval; 207 } 208 209 /* 210 * Log writes to the log buffer, and guarantees not to sleep (so can be 211 * called by interrupt routines). If there is no process reading the 212 * log yet, it writes to the console also. 213 */ 214 int 215 log(int level, const char *fmt, ...) 216 { 217 __va_list ap; 218 int retval; 219 struct putchar_arg pca; 220 221 pca.tty = NULL; 222 pca.pri = level; 223 pca.flags = log_open ? TOLOG : TOCONS; 224 225 __va_start(ap, fmt); 226 retval = kvprintf(fmt, putchar, &pca, 10, ap); 227 __va_end(ap); 228 229 msgbuftrigger = 1; 230 return (retval); 231 } 232 233 int 234 addlog(const char *fmt, ...) 235 { 236 __va_list ap; 237 int retval; 238 struct putchar_arg pca; 239 240 pca.tty = NULL; 241 pca.pri = -1; 242 pca.flags = log_open ? TOLOG : TOCONS; 243 244 __va_start(ap, fmt); 245 retval = kvprintf(fmt, putchar, &pca, 10, ap); 246 __va_end(ap); 247 248 msgbuftrigger = 1; 249 return (retval); 250 } 251 252 #define CONSCHUNK 128 253 254 void 255 log_console(struct uio *uio) 256 { 257 int c, i, error, iovlen, nl; 258 struct uio muio; 259 struct iovec *miov = NULL; 260 char *consbuffer; 261 int pri; 262 263 if (!log_console_output) 264 return; 265 266 pri = LOG_INFO | LOG_CONSOLE; 267 muio = *uio; 268 iovlen = uio->uio_iovcnt * sizeof (struct iovec); 269 MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 270 MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK); 271 bcopy((caddr_t)muio.uio_iov, (caddr_t)miov, iovlen); 272 muio.uio_iov = miov; 273 uio = &muio; 274 275 nl = 0; 276 while (uio->uio_resid > 0) { 277 c = imin(uio->uio_resid, CONSCHUNK); 278 error = uiomove(consbuffer, c, uio); 279 if (error != 0) 280 return; 281 for (i = 0; i < c; i++) { 282 msglogchar(consbuffer[i], pri); 283 if (consbuffer[i] == '\n') 284 nl = 1; 285 else 286 nl = 0; 287 } 288 } 289 if (!nl) 290 msglogchar('\n', pri); 291 msgbuftrigger = 1; 292 FREE(miov, M_TEMP); 293 FREE(consbuffer, M_TEMP); 294 return; 295 } 296 297 int 298 printf(const char *fmt, ...) 299 { 300 __va_list ap; 301 int savintr; 302 struct putchar_arg pca; 303 int retval; 304 305 savintr = consintr; /* disable interrupts */ 306 consintr = 0; 307 __va_start(ap, fmt); 308 pca.tty = NULL; 309 pca.flags = TOCONS | TOLOG; 310 pca.pri = -1; 311 cons_lock(); 312 retval = kvprintf(fmt, putchar, &pca, 10, ap); 313 cons_unlock(); 314 __va_end(ap); 315 if (!panicstr) 316 msgbuftrigger = 1; 317 consintr = savintr; /* reenable interrupts */ 318 return retval; 319 } 320 321 int 322 vprintf(const char *fmt, __va_list ap) 323 { 324 int savintr; 325 struct putchar_arg pca; 326 int retval; 327 328 savintr = consintr; /* disable interrupts */ 329 consintr = 0; 330 pca.tty = NULL; 331 pca.flags = TOCONS | TOLOG; 332 pca.pri = -1; 333 cons_lock(); 334 retval = kvprintf(fmt, putchar, &pca, 10, ap); 335 cons_unlock(); 336 if (!panicstr) 337 msgbuftrigger = 1; 338 consintr = savintr; /* reenable interrupts */ 339 return retval; 340 } 341 342 /* 343 * Print a character on console or users terminal. If destination is 344 * the console then the last bunch of characters are saved in msgbuf for 345 * inspection later. 346 */ 347 static void 348 putchar(int c, void *arg) 349 { 350 struct putchar_arg *ap = (struct putchar_arg*) arg; 351 int flags = ap->flags; 352 struct tty *tp = ap->tty; 353 if (panicstr) 354 constty = NULL; 355 if ((flags & TOCONS) && tp == NULL && constty) { 356 tp = constty; 357 flags |= TOTTY; 358 } 359 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 360 (flags & TOCONS) && tp == constty) 361 constty = NULL; 362 if ((flags & TOLOG)) 363 msglogchar(c, ap->pri); 364 if ((flags & TOCONS) && constty == NULL && c != '\0') 365 (*v_putc)(c); 366 } 367 368 /* 369 * Scaled down version of sprintf(3). 370 */ 371 int 372 sprintf(char *buf, const char *cfmt, ...) 373 { 374 int retval; 375 __va_list ap; 376 377 __va_start(ap, cfmt); 378 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 379 buf[retval] = '\0'; 380 __va_end(ap); 381 return retval; 382 } 383 384 /* 385 * Scaled down version of vsprintf(3). 386 */ 387 int 388 vsprintf(char *buf, const char *cfmt, __va_list ap) 389 { 390 int retval; 391 392 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 393 buf[retval] = '\0'; 394 return retval; 395 } 396 397 /* 398 * Scaled down version of snprintf(3). 399 */ 400 int 401 snprintf(char *str, size_t size, const char *format, ...) 402 { 403 int retval; 404 __va_list ap; 405 406 __va_start(ap, format); 407 retval = vsnprintf(str, size, format, ap); 408 __va_end(ap); 409 return(retval); 410 } 411 412 /* 413 * Scaled down version of vsnprintf(3). 414 */ 415 int 416 vsnprintf(char *str, size_t size, const char *format, __va_list ap) 417 { 418 struct snprintf_arg info; 419 int retval; 420 421 info.str = str; 422 info.remain = size; 423 retval = kvprintf(format, snprintf_func, &info, 10, ap); 424 if (info.remain >= 1) 425 *info.str++ = '\0'; 426 return retval; 427 } 428 429 static void 430 snprintf_func(int ch, void *arg) 431 { 432 struct snprintf_arg *const info = arg; 433 434 if (info->remain >= 2) { 435 *info->str++ = ch; 436 info->remain--; 437 } 438 } 439 440 /* 441 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 442 * order; return an optional length and a pointer to the last character 443 * written in the buffer (i.e., the first character of the string). 444 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 445 */ 446 static char * 447 ksprintn(nbuf, ul, base, lenp) 448 char *nbuf; 449 u_long ul; 450 int base, *lenp; 451 { 452 char *p; 453 454 p = nbuf; 455 *p = '\0'; 456 do { 457 *++p = hex2ascii(ul % base); 458 } while (ul /= base); 459 if (lenp) 460 *lenp = p - nbuf; 461 return (p); 462 } 463 /* ksprintn, but for a quad_t. */ 464 static char * 465 ksprintqn(nbuf, uq, base, lenp) 466 char *nbuf; 467 u_quad_t uq; 468 int base, *lenp; 469 { 470 char *p; 471 472 p = nbuf; 473 *p = '\0'; 474 do { 475 *++p = hex2ascii(uq % base); 476 } while (uq /= base); 477 if (lenp) 478 *lenp = p - nbuf; 479 return (p); 480 } 481 482 /* 483 * Scaled down version of printf(3). 484 * 485 * Two additional formats: 486 * 487 * The format %b is supported to decode error registers. 488 * Its usage is: 489 * 490 * printf("reg=%b\n", regval, "<base><arg>*"); 491 * 492 * where <base> is the output base expressed as a control character, e.g. 493 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 494 * the first of which gives the bit number to be inspected (origin 1), and 495 * the next characters (up to a control character, i.e. a character <= 32), 496 * give the name of the register. Thus: 497 * 498 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 499 * 500 * would produce output: 501 * 502 * reg=3<BITTWO,BITONE> 503 * 504 * XXX: %D -- Hexdump, takes pointer and separator string: 505 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 506 * ("%*D", len, ptr, " " -> XX XX XX XX ... 507 */ 508 int 509 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, __va_list ap) 510 { 511 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 512 char nbuf[MAXNBUF]; 513 char *p, *q, *d; 514 u_char *up; 515 int ch, n; 516 u_long ul; 517 u_quad_t uq; 518 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 519 int dwidth; 520 char padc; 521 int retval = 0; 522 523 ul = 0; 524 uq = 0; 525 if (!func) 526 d = (char *) arg; 527 else 528 d = NULL; 529 530 if (fmt == NULL) 531 fmt = "(fmt null)\n"; 532 533 if (radix < 2 || radix > 36) 534 radix = 10; 535 536 for (;;) { 537 padc = ' '; 538 width = 0; 539 while ((ch = (u_char)*fmt++) != '%') { 540 if (ch == '\0') 541 return retval; 542 PCHAR(ch); 543 } 544 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 545 sign = 0; dot = 0; dwidth = 0; 546 reswitch: switch (ch = (u_char)*fmt++) { 547 case '.': 548 dot = 1; 549 goto reswitch; 550 case '#': 551 sharpflag = 1; 552 goto reswitch; 553 case '+': 554 sign = 1; 555 goto reswitch; 556 case '-': 557 ladjust = 1; 558 goto reswitch; 559 case '%': 560 PCHAR(ch); 561 break; 562 case '*': 563 if (!dot) { 564 width = __va_arg(ap, int); 565 if (width < 0) { 566 ladjust = !ladjust; 567 width = -width; 568 } 569 } else { 570 dwidth = __va_arg(ap, int); 571 } 572 goto reswitch; 573 case '0': 574 if (!dot) { 575 padc = '0'; 576 goto reswitch; 577 } 578 case '1': case '2': case '3': case '4': 579 case '5': case '6': case '7': case '8': case '9': 580 for (n = 0;; ++fmt) { 581 n = n * 10 + ch - '0'; 582 ch = *fmt; 583 if (ch < '0' || ch > '9') 584 break; 585 } 586 if (dot) 587 dwidth = n; 588 else 589 width = n; 590 goto reswitch; 591 case 'b': 592 ul = __va_arg(ap, int); 593 p = __va_arg(ap, char *); 594 for (q = ksprintn(nbuf, ul, *p++, NULL); *q;) 595 PCHAR(*q--); 596 597 if (!ul) 598 break; 599 600 for (tmp = 0; *p;) { 601 n = *p++; 602 if (ul & (1 << (n - 1))) { 603 PCHAR(tmp ? ',' : '<'); 604 for (; (n = *p) > ' '; ++p) 605 PCHAR(n); 606 tmp = 1; 607 } else 608 for (; *p > ' '; ++p) 609 continue; 610 } 611 if (tmp) 612 PCHAR('>'); 613 break; 614 case 'c': 615 PCHAR(__va_arg(ap, int)); 616 break; 617 case 'D': 618 up = __va_arg(ap, u_char *); 619 p = __va_arg(ap, char *); 620 if (!width) 621 width = 16; 622 while(width--) { 623 PCHAR(hex2ascii(*up >> 4)); 624 PCHAR(hex2ascii(*up & 0x0f)); 625 up++; 626 if (width) 627 for (q=p;*q;q++) 628 PCHAR(*q); 629 } 630 break; 631 case 'd': 632 if (qflag) 633 uq = __va_arg(ap, quad_t); 634 else if (lflag) 635 ul = __va_arg(ap, long); 636 else 637 ul = __va_arg(ap, int); 638 sign = 1; 639 base = 10; 640 goto number; 641 case 'l': 642 if (lflag) { 643 lflag = 0; 644 qflag = 1; 645 } else 646 lflag = 1; 647 goto reswitch; 648 case 'o': 649 if (qflag) 650 uq = __va_arg(ap, u_quad_t); 651 else if (lflag) 652 ul = __va_arg(ap, u_long); 653 else 654 ul = __va_arg(ap, u_int); 655 base = 8; 656 goto nosign; 657 case 'p': 658 ul = (uintptr_t)__va_arg(ap, void *); 659 base = 16; 660 sharpflag = (width == 0); 661 goto nosign; 662 case 'q': 663 qflag = 1; 664 goto reswitch; 665 case 'n': 666 case 'r': 667 if (qflag) 668 uq = __va_arg(ap, u_quad_t); 669 else if (lflag) 670 ul = __va_arg(ap, u_long); 671 else 672 ul = sign ? 673 (u_long)__va_arg(ap, int) : __va_arg(ap, u_int); 674 base = radix; 675 goto number; 676 case 's': 677 p = __va_arg(ap, char *); 678 if (p == NULL) 679 p = "(null)"; 680 if (!dot) 681 n = strlen (p); 682 else 683 for (n = 0; n < dwidth && p[n]; n++) 684 continue; 685 686 width -= n; 687 688 if (!ladjust && width > 0) 689 while (width--) 690 PCHAR(padc); 691 while (n--) 692 PCHAR(*p++); 693 if (ladjust && width > 0) 694 while (width--) 695 PCHAR(padc); 696 break; 697 case 'u': 698 if (qflag) 699 uq = __va_arg(ap, u_quad_t); 700 else if (lflag) 701 ul = __va_arg(ap, u_long); 702 else 703 ul = __va_arg(ap, u_int); 704 base = 10; 705 goto nosign; 706 case 'x': 707 case 'X': 708 if (qflag) 709 uq = __va_arg(ap, u_quad_t); 710 else if (lflag) 711 ul = __va_arg(ap, u_long); 712 else 713 ul = __va_arg(ap, u_int); 714 base = 16; 715 goto nosign; 716 case 'z': 717 if (qflag) 718 uq = __va_arg(ap, u_quad_t); 719 else if (lflag) 720 ul = __va_arg(ap, u_long); 721 else 722 ul = sign ? 723 (u_long)__va_arg(ap, int) : __va_arg(ap, u_int); 724 base = 16; 725 goto number; 726 nosign: sign = 0; 727 number: 728 if (qflag) { 729 if (sign && (quad_t)uq < 0) { 730 neg = 1; 731 uq = -(quad_t)uq; 732 } 733 p = ksprintqn(nbuf, uq, base, &tmp); 734 } else { 735 if (sign && (long)ul < 0) { 736 neg = 1; 737 ul = -(long)ul; 738 } 739 p = ksprintn(nbuf, ul, base, &tmp); 740 } 741 if (sharpflag && (qflag ? uq != 0 : ul != 0)) { 742 if (base == 8) 743 tmp++; 744 else if (base == 16) 745 tmp += 2; 746 } 747 if (neg) 748 tmp++; 749 750 if (!ladjust && width && (width -= tmp) > 0) 751 while (width--) 752 PCHAR(padc); 753 if (neg) 754 PCHAR('-'); 755 if (sharpflag && (qflag ? uq != 0 : ul != 0)) { 756 if (base == 8) { 757 PCHAR('0'); 758 } else if (base == 16) { 759 PCHAR('0'); 760 PCHAR('x'); 761 } 762 } 763 764 while (*p) 765 PCHAR(*p--); 766 767 if (ladjust && width && (width -= tmp) > 0) 768 while (width--) 769 PCHAR(padc); 770 771 break; 772 default: 773 PCHAR('%'); 774 if (lflag) 775 PCHAR('l'); 776 PCHAR(ch); 777 break; 778 } 779 } 780 #undef PCHAR 781 } 782 783 /* 784 * Put character in log buffer with a particular priority. 785 */ 786 static void 787 msglogchar(int c, int pri) 788 { 789 static int lastpri = -1; 790 static int dangling; 791 char nbuf[MAXNBUF]; 792 char *p; 793 794 if (!msgbufmapped) 795 return; 796 if (c == '\0' || c == '\r') 797 return; 798 if (pri != -1 && pri != lastpri) { 799 if (dangling) { 800 msgaddchar('\n', NULL); 801 dangling = 0; 802 } 803 msgaddchar('<', NULL); 804 for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;) 805 msgaddchar(*p--, NULL); 806 msgaddchar('>', NULL); 807 lastpri = pri; 808 } 809 msgaddchar(c, NULL); 810 if (c == '\n') { 811 dangling = 0; 812 lastpri = -1; 813 } else { 814 dangling = 1; 815 } 816 } 817 818 /* 819 * Put char in log buffer 820 */ 821 static void 822 msgaddchar(int c, void *dummy) 823 { 824 struct msgbuf *mbp; 825 826 if (!msgbufmapped) 827 return; 828 mbp = msgbufp; 829 mbp->msg_ptr[mbp->msg_bufx++] = c; 830 if (mbp->msg_bufx >= mbp->msg_size) 831 mbp->msg_bufx = 0; 832 /* If the buffer is full, keep the most recent data. */ 833 if (mbp->msg_bufr == mbp->msg_bufx) { 834 if (++mbp->msg_bufr >= mbp->msg_size) 835 mbp->msg_bufr = 0; 836 } 837 } 838 839 static void 840 msgbufcopy(struct msgbuf *oldp) 841 { 842 int pos; 843 844 pos = oldp->msg_bufr; 845 while (pos != oldp->msg_bufx) { 846 msglogchar(oldp->msg_ptr[pos], -1); 847 if (++pos >= oldp->msg_size) 848 pos = 0; 849 } 850 } 851 852 void 853 msgbufinit(void *ptr, size_t size) 854 { 855 char *cp; 856 static struct msgbuf *oldp = NULL; 857 858 size -= sizeof(*msgbufp); 859 cp = (char *)ptr; 860 msgbufp = (struct msgbuf *) (cp + size); 861 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size || 862 msgbufp->msg_bufx >= size || msgbufp->msg_bufr >= size) { 863 bzero(cp, size); 864 bzero(msgbufp, sizeof(*msgbufp)); 865 msgbufp->msg_magic = MSG_MAGIC; 866 msgbufp->msg_size = (char *)msgbufp - cp; 867 } 868 msgbufp->msg_ptr = cp; 869 if (msgbufmapped && oldp != msgbufp) 870 msgbufcopy(oldp); 871 msgbufmapped = 1; 872 oldp = msgbufp; 873 } 874 875 /* Sysctls for accessing/clearing the msgbuf */ 876 877 static int 878 sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS) 879 { 880 struct ucred *cred; 881 int error; 882 883 /* 884 * Only wheel or root can access the message log. 885 */ 886 if (unprivileged_read_msgbuf == 0) { 887 KKASSERT(req->td->td_proc); 888 cred = req->td->td_proc->p_ucred; 889 890 if ((cred->cr_prison || groupmember(0, cred) == 0) && 891 suser(req->td) != 0 892 ) { 893 return (EPERM); 894 } 895 } 896 897 /* 898 * Unwind the buffer, so that it's linear (possibly starting with 899 * some initial nulls). 900 */ 901 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx, 902 msgbufp->msg_size - msgbufp->msg_bufx, req); 903 if (error) 904 return (error); 905 if (msgbufp->msg_bufx > 0) { 906 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr, 907 msgbufp->msg_bufx, req); 908 } 909 return (error); 910 } 911 912 SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD, 913 0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer"); 914 915 static int msgbuf_clear; 916 917 static int 918 sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS) 919 { 920 int error; 921 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); 922 if (!error && req->newptr) { 923 /* Clear the buffer and reset write pointer */ 924 bzero(msgbufp->msg_ptr, msgbufp->msg_size); 925 msgbufp->msg_bufr = msgbufp->msg_bufx = 0; 926 msgbuf_clear = 0; 927 } 928 return (error); 929 } 930 931 SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear, 932 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0, 933 sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer"); 934 935 #include "opt_ddb.h" 936 #ifdef DDB 937 #include <ddb/ddb.h> 938 939 DB_SHOW_COMMAND(msgbuf, db_show_msgbuf) 940 { 941 int i, j; 942 943 if (!msgbufmapped) { 944 db_printf("msgbuf not mapped yet\n"); 945 return; 946 } 947 db_printf("msgbufp = %p\n", msgbufp); 948 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n", 949 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr, 950 msgbufp->msg_bufx, msgbufp->msg_ptr); 951 for (i = 0; i < msgbufp->msg_size; i++) { 952 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size; 953 db_printf("%c", msgbufp->msg_ptr[j]); 954 } 955 db_printf("\n"); 956 } 957 958 #endif /* DDB */ 959