hexdump.c revision 70239
185909Simp/*- 285909Simp * Copyright (c) 1986, 1988, 1991, 1993 3122116Sbde * The Regents of the University of California. All rights reserved. 4122116Sbde * (c) UNIX System Laboratories, Inc. 5122116Sbde * All or some portions of this file are derived from material licensed 6180012Sru * to the University of California by American Telephone and Telegraph 7240468Sbrooks * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8160440Sobrien * the permission of UNIX System Laboratories, Inc. 9210151Simp * 10239272Sgonzo * Redistribution and use in source and binary forms, with or without 11210151Simp * modification, are permitted provided that the following conditions 1285909Simp * are met: 1385909Simp * 1. Redistributions of source code must retain the above copyright 1485909Simp * notice, this list of conditions and the following disclaimer. 1585909Simp * 2. Redistributions in binary form must reproduce the above copyright 16175888Simp * notice, this list of conditions and the following disclaimer in the 17175888Simp * documentation and/or other materials provided with the distribution. 1885909Simp * 3. All advertising materials mentioning features or use of this software 19218538Simp * must display the following acknowledgement: 2085909Simp * This product includes software developed by the University of 2191512Sobrien * California, Berkeley and its contributors. 22240451Snp * 4. Neither the name of the University nor the names of its contributors 23116341Smarkm * may be used to endorse or promote products derived from this software 2485909Simp * without specific prior written permission. 2585909Simp * 2685909Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2785909Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28220863Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29140606Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30187103Sgnn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31220863Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32224882Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33224882Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34224882Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35140606Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36220863Sdim * SUCH DAMAGE. 37224882Snwhitehorn * 38220863Sdim * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 39240468Sbrooks * $FreeBSD: head/sys/kern/subr_prf.c 70239 2000-12-20 21:50:37Z phk $ 40127204Sobrien */ 41220863Sdim 42228868Sdim#include <sys/param.h> 43228868Sdim#include <sys/systm.h> 44228868Sdim#include <sys/kernel.h> 45140606Sobrien#include <sys/msgbuf.h> 46220863Sdim#include <sys/malloc.h> 47220863Sdim#include <sys/proc.h> 48124834Sru#include <sys/tty.h> 49124834Sru#include <sys/syslog.h> 5085909Simp#include <sys/cons.h> 5185909Simp#include <sys/uio.h> 5285909Simp 53160043Sobrien/* 54126890Strhodes * Note that stdarg.h and the ANSI style va_start macro is used for both 5585909Simp * ANSI and traditional C compilers. 56192901Sthompsa */ 57126890Strhodes#include <machine/stdarg.h> 58151605Sobrien 59151605Sobrien#define TOCONS 0x01 60130416Smlaier#define TOTTY 0x02 61130416Smlaier#define TOLOG 0x04 62149978Sobrien 63149978Sobrien/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 64149978Sobrien#define MAXNBUF (sizeof(quad_t) * NBBY + 1) 65149978Sobrien 66149978Sobrienstruct putchar_arg { 67185522Ssam int flags; 68250173Sadrian int pri; 69149978Sobrien struct tty *tty; 70149978Sobrien}; 71149978Sobrien 72149978Sobrienstruct snprintf_arg { 73229353Sgjb char *str; 74149978Sobrien size_t remain; 75149978Sobrien}; 76218792Snp 77218792Snpextern int log_open; 78183292Skmacy 79149978Sobrienstruct tty *constty; /* pointer to console "window" tty */ 80149978Sobrien 81160043Sobrienstatic void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 82150966Sglebiusstatic void msglogchar(int c, int pri); 83240468Sbrooksstatic void msgaddchar(int c, void *dummy); 84124834Srustatic void putchar __P((int ch, void *arg)); 85210311Sjmallettstatic char *ksprintn __P((char *nbuf, u_long num, int base, int *len)); 86132766Skanstatic char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len)); 87132766Skanstatic void snprintf_func __P((int ch, void *arg)); 88210311Sjmallett 89210311Sjmallettstatic int consintr = 1; /* Ok to handle console interrupts? */ 90215988Sjmallettstatic int msgbufmapped; /* Set when safe to use msgbuf */ 91210311Sjmallettint msgbuftrigger; 92215988Sjmallett 93210311Sjmallett/* 94210394Srpaulo * Warn that a system table is full. 95171239Speter */ 9685909Simpvoid 9785909Simptablefull(const char *tab) 9885909Simp{ 9985909Simp 100240468Sbrooks log(LOG_ERR, "%s: table is full\n", tab); 101232263Sdim} 102260495Sdim 103260495Sdim/* 104232263Sdim * Uprintf prints to the controlling terminal for the current process. 105232263Sdim * It may block if the tty queue is overfull. No message is printed if 10699923Sbde * the queue does not clear in a reasonable time. 107242715Sdim */ 108242715Sdimint 109242715Sdimuprintf(const char *fmt, ...) 110242715Sdim{ 11199932Sbde struct proc *p = curproc; 11299932Sbde va_list ap; 113242717Sdim struct putchar_arg pca; 114242717Sdim int retval = 0; 115242717Sdim 116242717Sdim if (p && p != idleproc && p->p_flag & P_CONTROLT && 11799932Sbde p->p_session->s_ttyvp) { 118242717Sdim va_start(ap, fmt); 11999923Sbde pca.tty = p->p_session->s_ttyp; 12099932Sbde pca.flags = TOTTY; 12185909Simp retval = kvprintf(fmt, putchar, &pca, 10, ap); 12291002Speter va_end(ap); 12385909Simp } 12485909Simp return retval; 12585909Simp} 12685909Simp 127116341Smarkm/* 128116341Smarkm * tprintf prints on the controlling terminal associated 129116341Smarkm * with the given session, possibly to the log as well. 13091002Speter */ 13191002Spetervoid 13291002Spetertprintf(struct proc *p, int pri, const char *fmt, ...) 133105489Smux{ 13485909Simp struct tty *tp = NULL; 135105462Smux int flags = 0, shld = 0; 136105462Smux va_list ap; 13785909Simp struct putchar_arg pca; 138239956Sjhb int retval; 139239957Sjhb 140239957Sjhb if (pri != -1) 141239955Sjhb flags |= TOLOG; 142233578Speter if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 143233578Speter SESSHOLD(p->p_session); 144253996Savg shld++; 145233578Speter if (ttycheckoutq(p->p_session->s_ttyp, 0)) { 146233578Speter flags |= TOTTY; 147233578Speter tp = p->p_session->s_ttyp; 148233578Speter } 149228158Sfjoe } 150228140Sfjoe pca.pri = pri; 151228158Sfjoe pca.tty = tp; 152228158Sfjoe pca.flags = flags; 153228124Sfjoe va_start(ap, fmt); 154228158Sfjoe retval = kvprintf(fmt, putchar, &pca, 10, ap); 155228124Sfjoe va_end(ap); 156179226Sjb if (shld) 157116341Smarkm SESSRELE(p->p_session); 158116341Smarkm msgbuftrigger = 1; 159219819Sjeff} 160219819Sjeff 161219819Sjeff/* 162260495Sdim * Ttyprintf displays a message on a tty; it should be used only by 163219819Sjeff * the tty driver, or anything that knows the underlying tty will not 164219819Sjeff * be revoke(2)'d away. Other callers should use tprintf. 165219819Sjeff */ 166219819Sjeffint 167131210Simpttyprintf(struct tty *tp, const char *fmt, ...) 168144293Sphk{ 16985909Simp va_list ap; 170111684Sru struct putchar_arg pca; 171111684Sru int retval; 172111684Sru 173243664Smarcel va_start(ap, fmt); 17489180Smsmith pca.tty = tp; 17585909Simp pca.flags = TOTTY; 17685909Simp retval = kvprintf(fmt, putchar, &pca, 10, ap); 177123966Sbde va_end(ap); 178175888Simp return retval; 17985909Simp} 18088893Simp 18188893Simp/* 18288893Simp * Log writes to the log buffer, and guarantees not to sleep (so can be 183221265Sbz * called by interrupt routines). If there is no process reading the 184210151Simp * log yet, it writes to the console also. 18590789Sphk */ 18690789Sphkvoid 18790789Sphklog(int level, const char *fmt, ...) 18888893Simp{ 18988893Simp va_list ap; 19088893Simp int retval; 191216746Scperciva struct putchar_arg pca; 192216746Scperciva 193216746Scperciva pca.tty = NULL; 19488893Simp pca.pri = level; 195125772Sru pca.flags = log_open ? TOLOG : TOCONS; 19688893Simp 197240402Sobrien va_start(ap, fmt); 198240402Sobrien retval = kvprintf(fmt, putchar, &pca, 10, ap); 199240402Sobrien va_end(ap); 200240402Sobrien 201240402Sobrien msgbuftrigger = 1 202} 203 204#define CONSCHUNK 128 205 206void 207log_console(struct uio *uio) 208{ 209 int c, i, error, iovlen, nl; 210 struct uio muio; 211 struct iovec *miov = NULL; 212 char *consbuffer; 213 int pri; 214 215 pri = LOG_INFO | LOG_CONSOLE; 216 muio = *uio; 217 iovlen = uio->uio_iovcnt * sizeof (struct iovec); 218 MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK); 219 MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK); 220 bcopy((caddr_t)muio.uio_iov, (caddr_t)miov, iovlen); 221 muio.uio_iov = miov; 222 uio = &muio; 223 224 nl = 0; 225 while (uio->uio_resid > 0) { 226 c = imin(uio->uio_resid, CONSCHUNK); 227 error = uiomove(consbuffer, c, uio); 228 if (error != 0) 229 return; 230 for (i = 0; i < c; i++) { 231 msglogchar(consbuffer[i], pri); 232 if (consbuffer[i] == '\n') 233 nl = 1; 234 else 235 nl = 0; 236 } 237 } 238 if (!nl) 239 msglogchar('\n', pri); 240 msgbuftrigger = 1 241 FREE(miov, M_TEMP); 242 FREE(consbuffer, M_TEMP); 243 return; 244} 245 246int 247printf(const char *fmt, ...) 248{ 249 va_list ap; 250 int savintr; 251 struct putchar_arg pca; 252 int retval; 253 254 savintr = consintr; /* disable interrupts */ 255 consintr = 0; 256 va_start(ap, fmt); 257 pca.tty = NULL; 258 pca.flags = TOCONS | TOLOG; 259 pca.pri = -1; 260 retval = kvprintf(fmt, putchar, &pca, 10, ap); 261 va_end(ap); 262 if (!panicstr) 263 msgbuftrigger = 1 264 consintr = savintr; /* reenable interrupts */ 265 return retval; 266} 267 268int 269vprintf(const char *fmt, va_list ap) 270{ 271 int savintr; 272 struct putchar_arg pca; 273 int retval; 274 275 savintr = consintr; /* disable interrupts */ 276 consintr = 0; 277 pca.tty = NULL; 278 pca.flags = TOCONS | TOLOG; 279 pca.pri = -1; 280 retval = kvprintf(fmt, putchar, &pca, 10, ap); 281 if (!panicstr) 282 msgbuftrigger = 1 283 consintr = savintr; /* reenable interrupts */ 284 return retval; 285} 286 287/* 288 * Print a character on console or users terminal. If destination is 289 * the console then the last bunch of characters are saved in msgbuf for 290 * inspection later. 291 */ 292static void 293putchar(int c, void *arg) 294{ 295 struct putchar_arg *ap = (struct putchar_arg*) arg; 296 int flags = ap->flags; 297 struct tty *tp = ap->tty; 298 if (panicstr) 299 constty = NULL; 300 if ((flags & TOCONS) && tp == NULL && constty) { 301 tp = constty; 302 flags |= TOTTY; 303 } 304 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 305 (flags & TOCONS) && tp == constty) 306 constty = NULL; 307 if ((flags & TOLOG)) 308 msglogchar(c, ap->pri); 309 if ((flags & TOCONS) && constty == NULL && c != '\0') 310 (*v_putc)(c); 311} 312 313/* 314 * Scaled down version of sprintf(3). 315 */ 316int 317sprintf(char *buf, const char *cfmt, ...) 318{ 319 int retval; 320 va_list ap; 321 322 va_start(ap, cfmt); 323 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 324 buf[retval] = '\0'; 325 va_end(ap); 326 return retval; 327} 328 329/* 330 * Scaled down version of vsprintf(3). 331 */ 332int 333vsprintf(char *buf, const char *cfmt, va_list ap) 334{ 335 int retval; 336 337 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 338 buf[retval] = '\0'; 339 return retval; 340} 341 342/* 343 * Scaled down version of snprintf(3). 344 */ 345int 346snprintf(char *str, size_t size, const char *format, ...) 347{ 348 int retval; 349 va_list ap; 350 351 va_start(ap, format); 352 retval = vsnprintf(str, size, format, ap); 353 va_end(ap); 354 return(retval); 355} 356 357/* 358 * Scaled down version of vsnprintf(3). 359 */ 360int 361vsnprintf(char *str, size_t size, const char *format, va_list ap) 362{ 363 struct snprintf_arg info; 364 int retval; 365 366 info.str = str; 367 info.remain = size; 368 retval = kvprintf(format, snprintf_func, &info, 10, ap); 369 if (info.remain >= 1) 370 *info.str++ = '\0'; 371 return retval; 372} 373 374static void 375snprintf_func(int ch, void *arg) 376{ 377 struct snprintf_arg *const info = arg; 378 379 if (info->remain >= 2) { 380 *info->str++ = ch; 381 info->remain--; 382 } 383} 384 385/* 386 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 387 * order; return an optional length and a pointer to the last character 388 * written in the buffer (i.e., the first character of the string). 389 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 390 */ 391static char * 392ksprintn(nbuf, ul, base, lenp) 393 char *nbuf; 394 u_long ul; 395 int base, *lenp; 396{ 397 char *p; 398 399 p = nbuf; 400 *p = '\0'; 401 do { 402 *++p = hex2ascii(ul % base); 403 } while (ul /= base); 404 if (lenp) 405 *lenp = p - nbuf; 406 return (p); 407} 408/* ksprintn, but for a quad_t. */ 409static char * 410ksprintqn(nbuf, uq, base, lenp) 411 char *nbuf; 412 u_quad_t uq; 413 int base, *lenp; 414{ 415 char *p; 416 417 p = nbuf; 418 *p = '\0'; 419 do { 420 *++p = hex2ascii(uq % base); 421 } while (uq /= base); 422 if (lenp) 423 *lenp = p - nbuf; 424 return (p); 425} 426 427/* 428 * Scaled down version of printf(3). 429 * 430 * Two additional formats: 431 * 432 * The format %b is supported to decode error registers. 433 * Its usage is: 434 * 435 * printf("reg=%b\n", regval, "<base><arg>*"); 436 * 437 * where <base> is the output base expressed as a control character, e.g. 438 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 439 * the first of which gives the bit number to be inspected (origin 1), and 440 * the next characters (up to a control character, i.e. a character <= 32), 441 * give the name of the register. Thus: 442 * 443 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 444 * 445 * would produce output: 446 * 447 * reg=3<BITTWO,BITONE> 448 * 449 * XXX: %D -- Hexdump, takes pointer and separator string: 450 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 451 * ("%*D", len, ptr, " " -> XX XX XX XX ... 452 */ 453int 454kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 455{ 456#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 457 char nbuf[MAXNBUF]; 458 char *p, *q, *d; 459 u_char *up; 460 int ch, n; 461 u_long ul; 462 u_quad_t uq; 463 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 464 int dwidth; 465 char padc; 466 int retval = 0; 467 468 ul = 0; 469 uq = 0; 470 if (!func) 471 d = (char *) arg; 472 else 473 d = NULL; 474 475 if (fmt == NULL) 476 fmt = "(fmt null)\n"; 477 478 if (radix < 2 || radix > 36) 479 radix = 10; 480 481 for (;;) { 482 padc = ' '; 483 width = 0; 484 while ((ch = (u_char)*fmt++) != '%') { 485 if (ch == '\0') 486 return retval; 487 PCHAR(ch); 488 } 489 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 490 sign = 0; dot = 0; dwidth = 0; 491reswitch: switch (ch = (u_char)*fmt++) { 492 case '.': 493 dot = 1; 494 goto reswitch; 495 case '#': 496 sharpflag = 1; 497 goto reswitch; 498 case '+': 499 sign = 1; 500 goto reswitch; 501 case '-': 502 ladjust = 1; 503 goto reswitch; 504 case '%': 505 PCHAR(ch); 506 break; 507 case '*': 508 if (!dot) { 509 width = va_arg(ap, int); 510 if (width < 0) { 511 ladjust = !ladjust; 512 width = -width; 513 } 514 } else { 515 dwidth = va_arg(ap, int); 516 } 517 goto reswitch; 518 case '0': 519 if (!dot) { 520 padc = '0'; 521 goto reswitch; 522 } 523 case '1': case '2': case '3': case '4': 524 case '5': case '6': case '7': case '8': case '9': 525 for (n = 0;; ++fmt) { 526 n = n * 10 + ch - '0'; 527 ch = *fmt; 528 if (ch < '0' || ch > '9') 529 break; 530 } 531 if (dot) 532 dwidth = n; 533 else 534 width = n; 535 goto reswitch; 536 case 'b': 537 ul = va_arg(ap, int); 538 p = va_arg(ap, char *); 539 for (q = ksprintn(nbuf, ul, *p++, NULL); *q;) 540 PCHAR(*q--); 541 542 if (!ul) 543 break; 544 545 for (tmp = 0; *p;) { 546 n = *p++; 547 if (ul & (1 << (n - 1))) { 548 PCHAR(tmp ? ',' : '<'); 549 for (; (n = *p) > ' '; ++p) 550 PCHAR(n); 551 tmp = 1; 552 } else 553 for (; *p > ' '; ++p) 554 continue; 555 } 556 if (tmp) 557 PCHAR('>'); 558 break; 559 case 'c': 560 PCHAR(va_arg(ap, int)); 561 break; 562 case 'D': 563 up = va_arg(ap, u_char *); 564 p = va_arg(ap, char *); 565 if (!width) 566 width = 16; 567 while(width--) { 568 PCHAR(hex2ascii(*up >> 4)); 569 PCHAR(hex2ascii(*up & 0x0f)); 570 up++; 571 if (width) 572 for (q=p;*q;q++) 573 PCHAR(*q); 574 } 575 break; 576 case 'd': 577 if (qflag) 578 uq = va_arg(ap, quad_t); 579 else if (lflag) 580 ul = va_arg(ap, long); 581 else 582 ul = va_arg(ap, int); 583 sign = 1; 584 base = 10; 585 goto number; 586 case 'l': 587 if (lflag) { 588 lflag = 0; 589 qflag = 1; 590 } else 591 lflag = 1; 592 goto reswitch; 593 case 'o': 594 if (qflag) 595 uq = va_arg(ap, u_quad_t); 596 else if (lflag) 597 ul = va_arg(ap, u_long); 598 else 599 ul = va_arg(ap, u_int); 600 base = 8; 601 goto nosign; 602 case 'p': 603 ul = (uintptr_t)va_arg(ap, void *); 604 base = 16; 605 sharpflag = (width == 0); 606 goto nosign; 607 case 'q': 608 qflag = 1; 609 goto reswitch; 610 case 'n': 611 case 'r': 612 if (qflag) 613 uq = va_arg(ap, u_quad_t); 614 else if (lflag) 615 ul = va_arg(ap, u_long); 616 else 617 ul = sign ? 618 (u_long)va_arg(ap, int) : va_arg(ap, u_int); 619 base = radix; 620 goto number; 621 case 's': 622 p = va_arg(ap, char *); 623 if (p == NULL) 624 p = "(null)"; 625 if (!dot) 626 n = strlen (p); 627 else 628 for (n = 0; n < dwidth && p[n]; n++) 629 continue; 630 631 width -= n; 632 633 if (!ladjust && width > 0) 634 while (width--) 635 PCHAR(padc); 636 while (n--) 637 PCHAR(*p++); 638 if (ladjust && width > 0) 639 while (width--) 640 PCHAR(padc); 641 break; 642 case 'u': 643 if (qflag) 644 uq = va_arg(ap, u_quad_t); 645 else if (lflag) 646 ul = va_arg(ap, u_long); 647 else 648 ul = va_arg(ap, u_int); 649 base = 10; 650 goto nosign; 651 case 'x': 652 case 'X': 653 if (qflag) 654 uq = va_arg(ap, u_quad_t); 655 else if (lflag) 656 ul = va_arg(ap, u_long); 657 else 658 ul = va_arg(ap, u_int); 659 base = 16; 660 goto nosign; 661 case 'z': 662 if (qflag) 663 uq = va_arg(ap, u_quad_t); 664 else if (lflag) 665 ul = va_arg(ap, u_long); 666 else 667 ul = sign ? 668 (u_long)va_arg(ap, int) : va_arg(ap, u_int); 669 base = 16; 670 goto number; 671nosign: sign = 0; 672number: 673 if (qflag) { 674 if (sign && (quad_t)uq < 0) { 675 neg = 1; 676 uq = -(quad_t)uq; 677 } 678 p = ksprintqn(nbuf, uq, base, &tmp); 679 } else { 680 if (sign && (long)ul < 0) { 681 neg = 1; 682 ul = -(long)ul; 683 } 684 p = ksprintn(nbuf, ul, base, &tmp); 685 } 686 if (sharpflag && (qflag ? uq != 0 : ul != 0)) { 687 if (base == 8) 688 tmp++; 689 else if (base == 16) 690 tmp += 2; 691 } 692 if (neg) 693 tmp++; 694 695 if (!ladjust && width && (width -= tmp) > 0) 696 while (width--) 697 PCHAR(padc); 698 if (neg) 699 PCHAR('-'); 700 if (sharpflag && (qflag ? uq != 0 : ul != 0)) { 701 if (base == 8) { 702 PCHAR('0'); 703 } else if (base == 16) { 704 PCHAR('0'); 705 PCHAR('x'); 706 } 707 } 708 709 while (*p) 710 PCHAR(*p--); 711 712 if (ladjust && width && (width -= tmp) > 0) 713 while (width--) 714 PCHAR(padc); 715 716 break; 717 default: 718 PCHAR('%'); 719 if (lflag) 720 PCHAR('l'); 721 PCHAR(ch); 722 break; 723 } 724 } 725#undef PCHAR 726} 727 728/* 729 * Put character in log buffer with a particular priority. 730 */ 731static void 732msglogchar(int c, int pri) 733{ 734 static int lastpri = -1; 735 static int dangling; 736 char nbuf[MAXNBUF]; 737 char *p; 738 739 if (!msgbufmapped) 740 return; 741 if (c == '\0' || c == '\r') 742 return; 743 if (pri != -1 && pri != lastpri) { 744 if (dangling) { 745 msgaddchar('\n', NULL); 746 dangling = 0; 747 } 748 msgaddchar('<', NULL); 749 for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;) 750 msgaddchar(*p--, NULL); 751 msgaddchar('>', NULL); 752 lastpri = pri; 753 } 754 msgaddchar(c, NULL); 755 if (c == '\n') { 756 dangling = 0; 757 lastpri = -1; 758 } else { 759 dangling = 1; 760 } 761} 762 763/* 764 * Put char in log buffer 765 */ 766static void 767msgaddchar(int c, void *dummy) 768{ 769 struct msgbuf *mbp; 770 771 if (!msgbufmapped) 772 return; 773 mbp = msgbufp; 774 mbp->msg_ptr[mbp->msg_bufx++] = c; 775 if (mbp->msg_bufx >= mbp->msg_size) 776 mbp->msg_bufx = 0; 777 /* If the buffer is full, keep the most recent data. */ 778 if (mbp->msg_bufr == mbp->msg_bufx) { 779 if (++mbp->msg_bufr >= mbp->msg_size) 780 mbp->msg_bufr = 0; 781 } 782} 783 784static void 785msgbufcopy(struct msgbuf *oldp) 786{ 787 int pos; 788 789 pos = oldp->msg_bufr; 790 while (pos != oldp->msg_bufx) { 791 msglogchar(oldp->msg_ptr[pos], -1); 792 if (++pos >= oldp->msg_size) 793 pos = 0; 794 } 795} 796 797void 798msgbufinit(void *ptr, size_t size) 799{ 800 char *cp; 801 static struct msgbuf *oldp = NULL; 802 803 cp = (char *)ptr; 804 msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp)); 805 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) { 806 bzero(cp, size); 807 msgbufp->msg_magic = MSG_MAGIC; 808 msgbufp->msg_size = (char *)msgbufp - cp; 809 msgbufp->msg_ptr = cp; 810 } 811 if (msgbufmapped && oldp != msgbufp) 812 msgbufcopy(oldp); 813 msgbufmapped = 1; 814 oldp = msgbufp; 815} 816 817#include "opt_ddb.h" 818#ifdef DDB 819#include <ddb/ddb.h> 820 821DB_SHOW_COMMAND(msgbuf, db_show_msgbuf) 822{ 823 int i, j; 824 825 if (!msgbufmapped) { 826 db_printf("msgbuf not mapped yet\n"); 827 return; 828 } 829 db_printf("msgbufp = %p\n", msgbufp); 830 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n", 831 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr, 832 msgbufp->msg_bufx, msgbufp->msg_ptr); 833 for (i = 0; i < msgbufp->msg_size; i++) { 834 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size; 835 db_printf("%c", msgbufp->msg_ptr[j]); 836 } 837 db_printf("\n"); 838} 839 840#endif /* DDB */ 841