hexdump.c revision 13563
197318Sphk/*- 297318Sphk * Copyright (c) 1986, 1988, 1991, 1993 397318Sphk * The Regents of the University of California. All rights reserved. 497318Sphk * (c) UNIX System Laboratories, Inc. 597318Sphk * All or some portions of this file are derived from material licensed 697318Sphk * to the University of California by American Telephone and Telegraph 797318Sphk * Co. or Unix System Laboratories, Inc. and are reproduced herein with 897318Sphk * the permission of UNIX System Laboratories, Inc. 997318Sphk * 1097318Sphk * Redistribution and use in source and binary forms, with or without 1197318Sphk * modification, are permitted provided that the following conditions 1297318Sphk * are met: 1397318Sphk * 1. Redistributions of source code must retain the above copyright 1497318Sphk * notice, this list of conditions and the following disclaimer. 1597318Sphk * 2. Redistributions in binary form must reproduce the above copyright 1697318Sphk * notice, this list of conditions and the following disclaimer in the 1797318Sphk * documentation and/or other materials provided with the distribution. 1897318Sphk * 3. All advertising materials mentioning features or use of this software 1997318Sphk * must display the following acknowledgement: 2097318Sphk * This product includes software developed by the University of 2197318Sphk * California, Berkeley and its contributors. 2297318Sphk * 4. Neither the name of the University nor the names of its contributors 2397318Sphk * may be used to endorse or promote products derived from this software 2497318Sphk * without specific prior written permission. 2597318Sphk * 2697318Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2797318Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2897318Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2997318Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3097318Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3197318Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3297318Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3397318Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34139778Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35139778Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36139778Simp * SUCH DAMAGE. 3797318Sphk * 3897318Sphk * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 3997318Sphk * $Id: subr_prf.c,v 1.25 1996/01/19 21:05:52 phk Exp $ 4097318Sphk */ 4197318Sphk 4297318Sphk#include "opt_ddb.h" 43116196Sobrien 44116196Sobrien#include <sys/param.h> 45116196Sobrien#include <sys/systm.h> 4697318Sphk#include <sys/reboot.h> 4797318Sphk#include <sys/msgbuf.h> 4897318Sphk#include <sys/proc.h> 4997318Sphk#include <sys/vnode.h> 5097318Sphk#include <sys/tty.h> 5197318Sphk#include <sys/tprintf.h> 5297318Sphk#include <sys/syslog.h> 5397318Sphk#include <sys/malloc.h> 5498987Sphk#include <machine/cons.h> 55104087Sphk 5698987Sphk/* 5797318Sphk * Note that stdarg.h and the ANSI style va_start macro is used for both 5897318Sphk * ANSI and traditional C compilers. 5997318Sphk */ 60143418Sume#include <machine/stdarg.h> 6197318Sphk 6297318Sphk#ifdef KADB 6397318Sphk#include <machine/kdbparam.h> 6498987Sphk#endif 6598987Sphk 66107953Sphk 67107953Sphk#define TOCONS 0x01 68107953Sphk#define TOTTY 0x02 6997318Sphk#define TOLOG 0x04 7097318Sphk 7197318Sphkstruct tty *constty; /* pointer to console "window" tty */ 7298987Sphk 7398987Sphkstatic void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 7498987Sphk 7598987Sphkstatic void logpri __P((int level)); 7698987Sphkstatic void msglogchar(int c, void *dummyarg); 7797318Sphkstruct putchar_arg {int flags; struct tty *tty; }; 7897318Sphkstatic void putchar __P((int ch, void *arg)); 7997318Sphkstatic char *ksprintn __P((u_long num, int base, int *len)); 8098987Sphk 8197318Sphkstatic int consintr = 1; /* Ok to handle console interrupts? */ 8297318Sphk 8398987Sphk/* 8498987Sphk * Variable panicstr contains argument to first call to panic; used as flag 8598987Sphk * to indicate that the kernel has already called panic. 8698987Sphk */ 8798987Sphkconst char *panicstr; 8898987Sphk 8998987Sphk/* 9098987Sphk * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 9198987Sphk * and then reboots. If we are called twice, then we avoid trying to sync 9298987Sphk * the disks as this often leads to recursive panics. 9398987Sphk */ 9498987Sphk#ifdef __GNUC__ 9598987Sphk__dead /* panic() does not return */ 9698987Sphk#endif 9797318Sphkvoid 9898987Sphkpanic(const char *fmt, ...) 9998987Sphk{ 10098987Sphk int bootopt; 10198987Sphk va_list ap; 10298987Sphk 10398987Sphk bootopt = RB_AUTOBOOT | RB_DUMP; 10498987Sphk if (panicstr) 10598987Sphk bootopt |= RB_NOSYNC; 10698987Sphk else 10798987Sphk panicstr = fmt; 10898987Sphk 10998987Sphk va_start(ap, fmt); 11098987Sphk printf("panic: %r\n", fmt, ap); 11198987Sphk va_end(ap); 11298987Sphk 11398987Sphk#ifdef KGDB 11498987Sphk kgdb_panic(); 11598987Sphk#endif 11698987Sphk#ifdef KADB 11798987Sphk if (boothowto & RB_KDB) 11898987Sphk kdbpanic(); 11998987Sphk#endif 12098987Sphk#ifdef DDB 12198987Sphk Debugger ("panic"); 12298987Sphk#endif 12398987Sphk boot(bootopt); 12498987Sphk} 12598987Sphk 12698987Sphk/* 12798987Sphk * Warn that a system table is full. 12898987Sphk */ 12998987Sphkvoid 13098987Sphktablefull(tab) 13198987Sphk const char *tab; 13298987Sphk{ 13398987Sphk 13497318Sphk log(LOG_ERR, "%s: table is full\n", tab); 13597318Sphk} 13697318Sphk 13797318Sphk/* 13897318Sphk * Uprintf prints to the controlling terminal for the current process. 13998987Sphk * It may block if the tty queue is overfull. No message is printed if 14098987Sphk * the queue does not clear in a reasonable time. 14197318Sphk */ 14297318Sphkvoid 14397318Sphkuprintf(const char *fmt, ...) 144111119Simp{ 14597318Sphk struct proc *p = curproc; 14697318Sphk va_list ap; 14797318Sphk struct putchar_arg pca; 14898987Sphk 14997318Sphk if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 15098987Sphk va_start(ap, fmt); 15198987Sphk pca.tty = p->p_session->s_ttyp; 15297318Sphk pca.flags = TOTTY; 15398987Sphk kvprintf(fmt, putchar, &pca, 10, ap); 15497318Sphk va_end(ap); 15598987Sphk } 15698987Sphk} 15798987Sphk 15897318Sphktpr_t 15997318Sphktprintf_open(p) 16097318Sphk register struct proc *p; 16197318Sphk{ 16297318Sphk 16397318Sphk if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 16497318Sphk SESSHOLD(p->p_session); 16598987Sphk return ((tpr_t) p->p_session); 16697318Sphk } 16797318Sphk return ((tpr_t) NULL); 16897318Sphk} 16997318Sphk 17097318Sphkvoid 17197318Sphktprintf_close(sess) 17297318Sphk tpr_t sess; 17397318Sphk{ 17497318Sphk 17597318Sphk if (sess) 17697318Sphk SESSRELE((struct session *) sess); 17797318Sphk} 17898987Sphk 17998987Sphk/* 18097318Sphk * tprintf prints on the controlling terminal associated 18197318Sphk * with the given session. 18297318Sphk */ 18397318Sphkvoid 18497318Sphktprintf(tpr_t tpr, const char *fmt, ...) 18597318Sphk{ 18697318Sphk register struct session *sess = (struct session *)tpr; 187104057Sphk struct tty *tp = NULL; 188104195Sphk int flags = TOLOG; 189104057Sphk va_list ap; 190104057Sphk struct putchar_arg pca; 19197318Sphk 19297318Sphk logpri(LOG_INFO); 19397318Sphk if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 19497318Sphk flags |= TOTTY; 19597318Sphk tp = sess->s_ttyp; 19697318Sphk } 197104057Sphk va_start(ap, fmt); 198104195Sphk pca.tty = tp; 199104057Sphk pca.flags = flags; 200104057Sphk kvprintf(fmt, putchar, &pca, 10, ap); 20197318Sphk va_end(ap); 20297318Sphk logwakeup(); 203111119Simp} 20497318Sphk 20597318Sphk/* 20697318Sphk * Ttyprintf displays a message on a tty; it should be used only by 20797318Sphk * the tty driver, or anything that knows the underlying tty will not 20898987Sphk * be revoke(2)'d away. Other callers should use tprintf. 20997318Sphk */ 21098987Sphkvoid 21198987Sphkttyprintf(struct tty *tp, const char *fmt, ...) 21297318Sphk{ 21397318Sphk va_list ap; 21498987Sphk struct putchar_arg pca; 21597318Sphk va_start(ap, fmt); 21698987Sphk pca.tty = tp; 21797318Sphk pca.flags = TOTTY; 21897318Sphk kvprintf(fmt, putchar, &pca, 10, ap); 21997318Sphk va_end(ap); 22097318Sphk} 221104057Sphk 222104195Sphkextern int log_open; 223104057Sphk 224104057Sphk/* 22597318Sphk * Log writes to the log buffer, and guarantees not to sleep (so can be 22697318Sphk * called by interrupt routines). If there is no process reading the 22797318Sphk * log yet, it writes to the console also. 22897318Sphk */ 22997318Sphkvoid 230104195Sphklog(int level, const char *fmt, ...) 23197318Sphk{ 23297318Sphk register int s; 23397318Sphk va_list ap; 23497318Sphk 23597318Sphk s = splhigh(); 23697318Sphk logpri(level); 23797318Sphk va_start(ap, fmt); 23897318Sphk 23997318Sphk kvprintf(fmt, msglogchar, NULL, 10, ap); 24098987Sphk va_end(ap); 24197318Sphk 24297318Sphk splx(s); 24397318Sphk if (!log_open) { 24497318Sphk struct putchar_arg pca; 24597318Sphk va_start(ap, fmt); 24697318Sphk pca.tty = NULL; 24797318Sphk pca.flags = TOCONS; 24898987Sphk kvprintf(fmt, putchar, &pca, 10, ap); 249114532Sphk va_end(ap); 25098987Sphk } 251114532Sphk logwakeup(); 25297318Sphk} 25397318Sphk 25497318Sphkstatic void 25597318Sphklogpri(level) 25697318Sphk int level; 25797318Sphk{ 25897318Sphk register char *p; 25997318Sphk 26097318Sphk msglogchar('<', NULL); 26197318Sphk for (p = ksprintn((u_long)level, 10, NULL); *p;) 26297318Sphk msglogchar(*p--, NULL); 26397318Sphk msglogchar('>', NULL); 26497318Sphk} 26597318Sphk 26697318Sphkvoid 26797318Sphkaddlog(const char *fmt, ...) 26897318Sphk{ 269125755Sphk register int s; 27097318Sphk va_list ap; 27197318Sphk 27297318Sphk s = splhigh(); 27397318Sphk va_start(ap, fmt); 27497318Sphk kvprintf(fmt, msglogchar, NULL, 10, ap); 27597318Sphk splx(s); 27697318Sphk va_end(ap); 27797318Sphk if (!log_open) { 27897318Sphk struct putchar_arg pca; 27997318Sphk va_start(ap, fmt); 28097318Sphk pca.tty = NULL; 28197318Sphk pca.flags = TOCONS; 28297318Sphk kvprintf(fmt, putchar, &pca, 10, ap); 28397318Sphk va_end(ap); 28497318Sphk } 28597318Sphk logwakeup(); 28697318Sphk} 28797318Sphk 288125755Sphkvoid 28997318Sphkprintf(const char *fmt, ...) 29098066Sphk{ 29197318Sphk va_list ap; 29297318Sphk register int savintr; 29397318Sphk struct putchar_arg pca; 29497318Sphk 29597318Sphk savintr = consintr; /* disable interrupts */ 296104064Sphk consintr = 0; 297114491Sphk va_start(ap, fmt); 29897318Sphk pca.tty = NULL; 29997318Sphk pca.flags = TOCONS | TOLOG; 300105551Sphk kvprintf(fmt, putchar, &pca, 10, ap); 301105551Sphk va_end(ap); 302152971Ssobomax if (!panicstr) 303152967Ssobomax logwakeup(); 30497318Sphk consintr = savintr; /* reenable interrupts */ 30597318Sphk} 306111119Simp 30798987Sphkvoid 30898987Sphkvprintf(const char *fmt, va_list ap) 30998987Sphk{ 31098987Sphk register int savintr; 31198987Sphk struct putchar_arg pca; 31298987Sphk 31398987Sphk savintr = consintr; /* disable interrupts */ 31498987Sphk consintr = 0; 31598987Sphk pca.tty = NULL; 31698987Sphk pca.flags = TOCONS | TOLOG; 31797318Sphk kvprintf(fmt, putchar, &pca, 10, ap); 31898987Sphk if (!panicstr) 319114532Sphk logwakeup(); 32097318Sphk consintr = savintr; /* reenable interrupts */ 32197318Sphk} 32297318Sphk 32397318Sphk/* 32498987Sphk * Print a character on console or users terminal. If destination is 32598987Sphk * the console then the last MSGBUFS characters are saved in msgbuf for 32698987Sphk * inspection later. 32798987Sphk */ 32898987Sphkstatic void 329104087Sphkputchar(int c, void *arg) 33098987Sphk{ 33198987Sphk struct putchar_arg *ap = (struct putchar_arg*) arg; 33298987Sphk int flags = ap->flags; 33398987Sphk struct tty *tp = ap->tty; 33498987Sphk if (panicstr) 33598987Sphk constty = NULL; 33698987Sphk if ((flags & TOCONS) && tp == NULL && constty) { 33798987Sphk tp = constty; 338104087Sphk flags |= TOTTY; 33998987Sphk } 34098987Sphk if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 34198987Sphk (flags & TOCONS) && tp == constty) 34298987Sphk constty = NULL; 34398987Sphk if ((flags & TOLOG)) 34498987Sphk msglogchar(c, NULL); 34598987Sphk if ((flags & TOCONS) && constty == NULL && c != '\0') 346104064Sphk (*v_putc)(c); 34797318Sphk} 34897318Sphk 349105551Sphk/* 35097318Sphk * Scaled down version of sprintf(3). 351104064Sphk */ 352114491Sphkint 353104064Sphksprintf(char *buf, const char *cfmt, ...) 35497318Sphk{ 35597318Sphk int retval; 356125755Sphk va_list ap; 35797318Sphk 35897318Sphk va_start(ap, cfmt); 35998066Sphk retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap); 36097318Sphk buf[retval] = '\0'; 36197318Sphk va_end(ap); 36297318Sphk return retval; 36397318Sphk} 36497318Sphk 36597318Sphk/* 366112552Sphk * Put a number (base <= 16) in a buffer in reverse order; return an 367133318Sphk * optional length and a pointer to the NULL terminated (preceded?) 368112552Sphk * buffer. 369133314Sphk */ 370133314Sphkstatic char * 371133314Sphkksprintn(ul, base, lenp) 372133314Sphk register u_long ul; 37397318Sphk register int base, *lenp; 37497318Sphk{ /* A long in base 8, plus NULL. */ 37597318Sphk static char buf[sizeof(long) * NBBY / 3 + 2]; 376 register char *p; 377 378 p = buf; 379 do { 380 *++p = hex2ascii(ul % base); 381 } while (ul /= base); 382 if (lenp) 383 *lenp = p - buf; 384 return (p); 385} 386 387/* 388 * Scaled down version of printf(3). 389 * 390 * Two additional formats: 391 * 392 * The format %b is supported to decode error registers. 393 * Its usage is: 394 * 395 * printf("reg=%b\n", regval, "<base><arg>*"); 396 * 397 * where <base> is the output base expressed as a control character, e.g. 398 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 399 * the first of which gives the bit number to be inspected (origin 1), and 400 * the next characters (up to a control character, i.e. a character <= 32), 401 * give the name of the register. Thus: 402 * 403 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 404 * 405 * would produce output: 406 * 407 * reg=3<BITTWO,BITONE> 408 * 409 * The format %r passes an additional format string and argument list 410 * recursively. Its usage is: 411 * 412 * fn(char *fmt, ...) 413 * { 414 * va_list ap; 415 * va_start(ap, fmt); 416 * printf("prefix: %r: suffix\n", fmt, ap); 417 * va_end(ap); 418 * } 419 * 420 * Space or zero padding and a field width are supported for the numeric 421 * formats only. 422 */ 423int 424kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 425{ 426#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 427 char *p, *q, *d; 428 int ch, n; 429 u_long ul; 430 int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 431 int dwidth; 432 char padc; 433 int retval = 0; 434 435 if (!func) 436 d = (char *) arg; 437 else 438 d = NULL; 439 440 if (fmt == NULL) 441 fmt = "(fmt null)\n"; 442 443 if (radix < 8 || radix > 16) 444 radix = 10; 445 446 for (;;) { 447 padc = ' '; 448 width = 0; 449 while ((ch = *(u_char *)fmt++) != '%') { 450 if (ch == '\0') 451 return retval; 452 PCHAR(ch); 453 } 454 lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 455 sign = 0; dot = 0; dwidth = 0; 456reswitch: switch (ch = *(u_char *)fmt++) { 457 case '.': 458 dot = 1; 459 goto reswitch; 460 case '#': 461 sharpflag = 1; 462 goto reswitch; 463 case '+': 464 sign = 1; 465 goto reswitch; 466 case '-': 467 ladjust = 1; 468 goto reswitch; 469 case '%': 470 PCHAR(ch); 471 break; 472 case '*': 473 if (!dot) { 474 width = va_arg(ap, int); 475 if (width < 0) { 476 ladjust = !ladjust; 477 width = -width; 478 } 479 } else { 480 dwidth = va_arg(ap, int); 481 } 482 goto reswitch; 483 case '0': 484 if (!dot) { 485 padc = '0'; 486 goto reswitch; 487 } 488 case '1': case '2': case '3': case '4': 489 case '5': case '6': case '7': case '8': case '9': 490 for (n = 0;; ++fmt) { 491 n = n * 10 + ch - '0'; 492 ch = *fmt; 493 if (ch < '0' || ch > '9') 494 break; 495 } 496 if (dot) 497 dwidth = n; 498 else 499 width = n; 500 goto reswitch; 501 case 'b': 502 ul = va_arg(ap, int); 503 p = va_arg(ap, char *); 504 for (q = ksprintn(ul, *p++, NULL); *q;) 505 PCHAR(*q--); 506 507 if (!ul) 508 break; 509 510 for (tmp = 0; *p;) { 511 n = *p++; 512 if (ul & (1 << (n - 1))) { 513 PCHAR(tmp ? ',' : '<'); 514 for (; (n = *p) > ' '; ++p) 515 PCHAR(n); 516 tmp = 1; 517 } else 518 for (; *p > ' '; ++p) 519 continue; 520 } 521 if (tmp) 522 PCHAR('>'); 523 break; 524 case 'c': 525 PCHAR(va_arg(ap, int)); 526 break; 527 case 'd': 528 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 529 sign = 1; 530 base = 10; 531 goto number; 532 case 'l': 533 lflag = 1; 534 goto reswitch; 535 case 'n': 536 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 537 base = radix; 538 goto number; 539 case 'o': 540 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 541 base = 8; 542 goto number; 543 case 'p': 544 ul = (u_long)va_arg(ap, void *); 545 base = 16; 546 PCHAR('0'); 547 PCHAR('x'); 548 goto number; 549 case 'r': 550 p = va_arg(ap, char *); 551 if (!func) { 552 n = kvprintf(p, func, d, radix, ap); 553 d += n; 554 } else { 555 n = kvprintf(p, func, arg, radix, ap); 556 } 557 retval += n; 558 break; 559 case 's': 560 p = va_arg(ap, char *); 561 if (p == NULL) 562 p = "(null)"; 563 if (!dot) 564 n = strlen (p); 565 else 566 for (n = 0; n < dwidth && p[n]; n++) 567 continue; 568 569 width -= n; 570 571 if (!ladjust && width > 0) 572 while (width--) 573 PCHAR(padc); 574 while (n--) 575 PCHAR(*p++); 576 if (ladjust && width > 0) 577 while (width--) 578 PCHAR(padc); 579 break; 580 case 'u': 581 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 582 base = 10; 583 goto number; 584 case 'x': 585 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 586 base = 16; 587number: if (sign && (long)ul < 0L) { 588 neg = 1; 589 ul = -(long)ul; 590 } 591 p = ksprintn(ul, base, &tmp); 592 if (sharpflag && ul != 0) { 593 if (base == 8) 594 tmp++; 595 else if (base == 16) 596 tmp += 2; 597 } 598 if (neg) 599 tmp++; 600 601 if (!ladjust && width && (width -= tmp) > 0) 602 while (width--) 603 PCHAR(padc); 604 if (neg) 605 PCHAR('-'); 606 if (sharpflag && ul != 0) { 607 if (base == 8) { 608 PCHAR('0'); 609 } else if (base == 16) { 610 PCHAR('0'); 611 PCHAR('x'); 612 } 613 } 614 615 while (*p) 616 PCHAR(*p--); 617 618 if (ladjust && width && (width -= tmp) > 0) 619 while (width--) 620 PCHAR(padc); 621 622 break; 623 default: 624 PCHAR('%'); 625 if (lflag) 626 PCHAR('l'); 627 PCHAR(ch); 628 break; 629 } 630 } 631#undef PCHAR 632} 633 634/* 635 * Put character in log buffer. 636 */ 637static void 638msglogchar(int c, void *dummyarg) 639{ 640 struct msgbuf *mbp; 641 642 if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 643 mbp = msgbufp; 644 if (mbp->msg_magic != MSG_MAGIC || 645 mbp->msg_bufx >= MSG_BSIZE || 646 mbp->msg_bufr >= MSG_BSIZE) { 647 bzero(mbp, sizeof(struct msgbuf)); 648 mbp->msg_magic = MSG_MAGIC; 649 } 650 mbp->msg_bufc[mbp->msg_bufx++] = c; 651 if (mbp->msg_bufx >= MSG_BSIZE) 652 mbp->msg_bufx = 0; 653 /* If the buffer is full, keep the most recent data. */ 654 if (mbp->msg_bufr == mbp->msg_bufx) { 655 if (++mbp->msg_bufr >= MSG_BSIZE) 656 mbp->msg_bufr = 0; 657 } 658 } 659} 660