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