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