hexdump.c revision 65557
1109998Smarkm/*-
2280304Sjkim * Copyright (c) 1986, 1988, 1991, 1993
3280304Sjkim *	The Regents of the University of California.  All rights reserved.
4280304Sjkim * (c) UNIX System Laboratories, Inc.
5109998Smarkm * All or some portions of this file are derived from material licensed
6109998Smarkm * to the University of California by American Telephone and Telegraph
7109998Smarkm * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8109998Smarkm * the permission of UNIX System Laboratories, Inc.
9109998Smarkm *
10109998Smarkm * Redistribution and use in source and binary forms, with or without
11109998Smarkm * modification, are permitted provided that the following conditions
12109998Smarkm * are met:
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in the
17109998Smarkm *    documentation and/or other materials provided with the distribution.
18109998Smarkm * 3. All advertising materials mentioning features or use of this software
19109998Smarkm *    must display the following acknowledgement:
20109998Smarkm *	This product includes software developed by the University of
21109998Smarkm *	California, Berkeley and its contributors.
22109998Smarkm * 4. Neither the name of the University nor the names of its contributors
23109998Smarkm *    may be used to endorse or promote products derived from this software
24109998Smarkm *    without specific prior written permission.
25109998Smarkm *
26109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29109998Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34109998Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36109998Smarkm * SUCH DAMAGE.
37109998Smarkm *
38109998Smarkm *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
39109998Smarkm * $FreeBSD: head/sys/kern/subr_prf.c 65557 2000-09-07 01:33:02Z jasone $
40109998Smarkm */
41109998Smarkm
42109998Smarkm#include <sys/param.h>
43109998Smarkm#include <sys/systm.h>
44109998Smarkm#include <sys/kernel.h>
45109998Smarkm#include <sys/msgbuf.h>
46109998Smarkm#include <sys/malloc.h>
47109998Smarkm#include <sys/proc.h>
48109998Smarkm#include <sys/tty.h>
49109998Smarkm#include <sys/tprintf.h>
50109998Smarkm#include <sys/syslog.h>
51109998Smarkm#include <sys/cons.h>
52109998Smarkm
53109998Smarkm/*
54109998Smarkm * Note that stdarg.h and the ANSI style va_start macro is used for both
55109998Smarkm * ANSI and traditional C compilers.
56109998Smarkm */
57109998Smarkm#include <machine/stdarg.h>
58109998Smarkm
59109998Smarkm#define TOCONS	0x01
60109998Smarkm#define TOTTY	0x02
61109998Smarkm#define TOLOG	0x04
62109998Smarkm
63109998Smarkm/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
64109998Smarkm#define MAXNBUF	(sizeof(quad_t) * NBBY + 1)
65109998Smarkm
66109998Smarkmstruct putchar_arg {
67109998Smarkm	int	flags;
68280304Sjkim	struct	tty *tty;
69280304Sjkim};
70280304Sjkim
71280304Sjkimstruct snprintf_arg {
72280304Sjkim	char	*str;
73280304Sjkim	size_t	remain;
74280304Sjkim};
75280304Sjkim
76280304Sjkimstruct	tty *constty;			/* pointer to console "window" tty */
77109998Smarkm
78109998Smarkmstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
79280304Sjkimstatic void  logpri __P((int level));
80280304Sjkimstatic void  msglogchar(int c, void *dummyarg);
81280304Sjkimstatic void  putchar __P((int ch, void *arg));
82280304Sjkimstatic char *ksprintn __P((char *nbuf, u_long num, int base, int *len));
83280304Sjkimstatic char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len));
84109998Smarkmstatic void  snprintf_func __P((int ch, void *arg));
85238405Sjkim
86280304Sjkimstatic int consintr = 1;		/* Ok to handle console interrupts? */
87280304Sjkimstatic int msgbufmapped;		/* Set when safe to use msgbuf */
88109998Smarkm
89280304Sjkim/*
90280304Sjkim * Warn that a system table is full.
91280304Sjkim */
92280304Sjkimvoid
93280304Sjkimtablefull(tab)
94280304Sjkim	const char *tab;
95280304Sjkim{
96280304Sjkim
97280304Sjkim	log(LOG_ERR, "%s: table is full\n", tab);
98280304Sjkim}
99280304Sjkim
100280304Sjkim/*
101109998Smarkm * Uprintf prints to the controlling terminal for the current process.
102238405Sjkim * It may block if the tty queue is overfull.  No message is printed if
103280304Sjkim * the queue does not clear in a reasonable time.
104280304Sjkim */
105109998Smarkmint
106280304Sjkimuprintf(const char *fmt, ...)
107280304Sjkim{
108280304Sjkim	struct proc *p = curproc;
109280304Sjkim	va_list ap;
110280304Sjkim	struct putchar_arg pca;
111280304Sjkim	int retval = 0;
112280304Sjkim
113280304Sjkim	if (p && p != idleproc && p->p_flag & P_CONTROLT &&
114280304Sjkim	    p->p_session->s_ttyvp) {
115280304Sjkim		va_start(ap, fmt);
116280304Sjkim		pca.tty = p->p_session->s_ttyp;
117280304Sjkim		pca.flags = TOTTY;
118109998Smarkm		retval = kvprintf(fmt, putchar, &pca, 10, ap);
119109998Smarkm		va_end(ap);
120280304Sjkim	}
121280304Sjkim	return retval;
122280304Sjkim}
123280304Sjkim
124280304Sjkimtpr_t
125280304Sjkimtprintf_open(p)
126280304Sjkim	register struct proc *p;
127280304Sjkim{
128280304Sjkim
129280304Sjkim	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
130280304Sjkim		SESSHOLD(p->p_session);
131280304Sjkim		return ((tpr_t) p->p_session);
132280304Sjkim	}
133280304Sjkim	return ((tpr_t) NULL);
134109998Smarkm}
135109998Smarkm
136280304Sjkimvoid
137280304Sjkimtprintf_close(sess)
138109998Smarkm	tpr_t sess;
139280304Sjkim{
140280304Sjkim
141280304Sjkim	if (sess)
142280304Sjkim		SESSRELE((struct session *) sess);
143280304Sjkim}
144280304Sjkim
145280304Sjkim/*
146280304Sjkim * tprintf prints on the controlling terminal associated
147280304Sjkim * with the given session.
148280304Sjkim */
149280304Sjkimint
150280304Sjkimtprintf(tpr_t tpr, const char *fmt, ...)
151109998Smarkm{
152109998Smarkm	register struct session *sess = (struct session *)tpr;
153280304Sjkim	struct tty *tp = NULL;
154280304Sjkim	int flags = TOLOG;
155109998Smarkm	va_list ap;
156280304Sjkim	struct putchar_arg pca;
157280304Sjkim	int retval;
158280304Sjkim
159280304Sjkim	logpri(LOG_INFO);
160280304Sjkim	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
161280304Sjkim		flags |= TOTTY;
162280304Sjkim		tp = sess->s_ttyp;
163280304Sjkim	}
164280304Sjkim	va_start(ap, fmt);
165280304Sjkim	pca.tty = tp;
166280304Sjkim	pca.flags = flags;
167280304Sjkim	retval = kvprintf(fmt, putchar, &pca, 10, ap);
168	va_end(ap);
169	logwakeup();
170	return retval;
171}
172
173/*
174 * Ttyprintf displays a message on a tty; it should be used only by
175 * the tty driver, or anything that knows the underlying tty will not
176 * be revoke(2)'d away.  Other callers should use tprintf.
177 */
178int
179ttyprintf(struct tty *tp, const char *fmt, ...)
180{
181	va_list ap;
182	struct putchar_arg pca;
183	int retval;
184
185	va_start(ap, fmt);
186	pca.tty = tp;
187	pca.flags = TOTTY;
188	retval = kvprintf(fmt, putchar, &pca, 10, ap);
189	va_end(ap);
190	return retval;
191}
192
193extern	int log_open;
194
195/*
196 * Log writes to the log buffer, and guarantees not to sleep (so can be
197 * called by interrupt routines).  If there is no process reading the
198 * log yet, it writes to the console also.
199 */
200int
201log(int level, const char *fmt, ...)
202{
203	register int s;
204	va_list ap;
205	int retval;
206
207	s = splhigh();
208	logpri(level);
209	va_start(ap, fmt);
210
211	retval = kvprintf(fmt, msglogchar, NULL, 10, ap);
212	va_end(ap);
213
214	splx(s);
215	if (!log_open) {
216		struct putchar_arg pca;
217		va_start(ap, fmt);
218		pca.tty = NULL;
219		pca.flags = TOCONS;
220		retval += kvprintf(fmt, putchar, &pca, 10, ap);
221		va_end(ap);
222	}
223	logwakeup();
224	return retval;
225}
226
227static void
228logpri(level)
229	int level;
230{
231	char nbuf[MAXNBUF];
232	register char *p;
233
234	msglogchar('<', NULL);
235	for (p = ksprintn(nbuf, (u_long)level, 10, NULL); *p;)
236		msglogchar(*p--, NULL);
237	msglogchar('>', NULL);
238}
239
240int
241addlog(const char *fmt, ...)
242{
243	register int s;
244	va_list ap;
245	int retval;
246
247	s = splhigh();
248	va_start(ap, fmt);
249	retval = kvprintf(fmt, msglogchar, NULL, 10, ap);
250	splx(s);
251	va_end(ap);
252	if (!log_open) {
253		struct putchar_arg pca;
254		va_start(ap, fmt);
255		pca.tty = NULL;
256		pca.flags = TOCONS;
257		retval += kvprintf(fmt, putchar, &pca, 10, ap);
258		va_end(ap);
259	}
260	logwakeup();
261	return (retval);
262}
263
264int
265printf(const char *fmt, ...)
266{
267	va_list ap;
268	register int savintr;
269	struct putchar_arg pca;
270	int retval;
271
272	savintr = consintr;		/* disable interrupts */
273	consintr = 0;
274	va_start(ap, fmt);
275	pca.tty = NULL;
276	pca.flags = TOCONS | TOLOG;
277	retval = kvprintf(fmt, putchar, &pca, 10, ap);
278	va_end(ap);
279	if (!panicstr)
280		logwakeup();
281	consintr = savintr;		/* reenable interrupts */
282	return retval;
283}
284
285int
286vprintf(const char *fmt, va_list ap)
287{
288	register int savintr;
289	struct putchar_arg pca;
290	int retval;
291
292	savintr = consintr;		/* disable interrupts */
293	consintr = 0;
294	pca.tty = NULL;
295	pca.flags = TOCONS | TOLOG;
296	retval = kvprintf(fmt, putchar, &pca, 10, ap);
297	if (!panicstr)
298		logwakeup();
299	consintr = savintr;		/* reenable interrupts */
300	return retval;
301}
302
303/*
304 * Print a character on console or users terminal.  If destination is
305 * the console then the last bunch of characters are saved in msgbuf for
306 * inspection later.
307 */
308static void
309putchar(int c, void *arg)
310{
311	struct putchar_arg *ap = (struct putchar_arg*) arg;
312	int flags = ap->flags;
313	struct tty *tp = ap->tty;
314	if (panicstr)
315		constty = NULL;
316	if ((flags & TOCONS) && tp == NULL && constty) {
317		tp = constty;
318		flags |= TOTTY;
319	}
320	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
321	    (flags & TOCONS) && tp == constty)
322		constty = NULL;
323	if ((flags & TOLOG))
324		msglogchar(c, NULL);
325	if ((flags & TOCONS) && constty == NULL && c != '\0')
326		(*v_putc)(c);
327}
328
329/*
330 * Scaled down version of sprintf(3).
331 */
332int
333sprintf(char *buf, const char *cfmt, ...)
334{
335	int retval;
336	va_list ap;
337
338	va_start(ap, cfmt);
339	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
340	buf[retval] = '\0';
341	va_end(ap);
342	return retval;
343}
344
345/*
346 * Scaled down version of vsprintf(3).
347 */
348int
349vsprintf(char *buf, const char *cfmt, va_list ap)
350{
351	int retval;
352
353	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
354	buf[retval] = '\0';
355	return retval;
356}
357
358/*
359 * Scaled down version of snprintf(3).
360 */
361int
362snprintf(char *str, size_t size, const char *format, ...)
363{
364	int retval;
365	va_list ap;
366
367	va_start(ap, format);
368	retval = vsnprintf(str, size, format, ap);
369	va_end(ap);
370	return(retval);
371}
372
373/*
374 * Scaled down version of vsnprintf(3).
375 */
376int
377vsnprintf(char *str, size_t size, const char *format, va_list ap)
378{
379	struct snprintf_arg info;
380	int retval;
381
382	info.str = str;
383	info.remain = size;
384	retval = kvprintf(format, snprintf_func, &info, 10, ap);
385	if (info.remain >= 1)
386		*info.str++ = '\0';
387	return retval;
388}
389
390static void
391snprintf_func(int ch, void *arg)
392{
393	struct snprintf_arg *const info = arg;
394
395	if (info->remain >= 2) {
396		*info->str++ = ch;
397		info->remain--;
398	}
399}
400
401/*
402 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
403 * order; return an optional length and a pointer to the last character
404 * written in the buffer (i.e., the first character of the string).
405 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
406 */
407static char *
408ksprintn(nbuf, ul, base, lenp)
409	char *nbuf;
410	register u_long ul;
411	register int base, *lenp;
412{
413	register char *p;
414
415	p = nbuf;
416	*p = '\0';
417	do {
418		*++p = hex2ascii(ul % base);
419	} while (ul /= base);
420	if (lenp)
421		*lenp = p - nbuf;
422	return (p);
423}
424/* ksprintn, but for a quad_t. */
425static char *
426ksprintqn(nbuf, uq, base, lenp)
427	char *nbuf;
428	register u_quad_t uq;
429	register int base, *lenp;
430{
431	register char *p;
432
433	p = nbuf;
434	*p = '\0';
435	do {
436		*++p = hex2ascii(uq % base);
437	} while (uq /= base);
438	if (lenp)
439		*lenp = p - nbuf;
440	return (p);
441}
442
443/*
444 * Scaled down version of printf(3).
445 *
446 * Two additional formats:
447 *
448 * The format %b is supported to decode error registers.
449 * Its usage is:
450 *
451 *	printf("reg=%b\n", regval, "<base><arg>*");
452 *
453 * where <base> is the output base expressed as a control character, e.g.
454 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
455 * the first of which gives the bit number to be inspected (origin 1), and
456 * the next characters (up to a control character, i.e. a character <= 32),
457 * give the name of the register.  Thus:
458 *
459 *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
460 *
461 * would produce output:
462 *
463 *	reg=3<BITTWO,BITONE>
464 *
465 * XXX:  %D  -- Hexdump, takes pointer and separator string:
466 *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
467 *		("%*D", len, ptr, " " -> XX XX XX XX ...
468 */
469int
470kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
471{
472#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
473	char nbuf[MAXNBUF];
474	char *p, *q, *d;
475	u_char *up;
476	int ch, n;
477	u_long ul;
478	u_quad_t uq;
479	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
480	int dwidth;
481	char padc;
482	int retval = 0;
483
484	ul = 0;
485	uq = 0;
486	if (!func)
487		d = (char *) arg;
488	else
489		d = NULL;
490
491	if (fmt == NULL)
492		fmt = "(fmt null)\n";
493
494	if (radix < 2 || radix > 36)
495		radix = 10;
496
497	for (;;) {
498		padc = ' ';
499		width = 0;
500		while ((ch = (u_char)*fmt++) != '%') {
501			if (ch == '\0')
502				return retval;
503			PCHAR(ch);
504		}
505		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
506		sign = 0; dot = 0; dwidth = 0;
507reswitch:	switch (ch = (u_char)*fmt++) {
508		case '.':
509			dot = 1;
510			goto reswitch;
511		case '#':
512			sharpflag = 1;
513			goto reswitch;
514		case '+':
515			sign = 1;
516			goto reswitch;
517		case '-':
518			ladjust = 1;
519			goto reswitch;
520		case '%':
521			PCHAR(ch);
522			break;
523		case '*':
524			if (!dot) {
525				width = va_arg(ap, int);
526				if (width < 0) {
527					ladjust = !ladjust;
528					width = -width;
529				}
530			} else {
531				dwidth = va_arg(ap, int);
532			}
533			goto reswitch;
534		case '0':
535			if (!dot) {
536				padc = '0';
537				goto reswitch;
538			}
539		case '1': case '2': case '3': case '4':
540		case '5': case '6': case '7': case '8': case '9':
541				for (n = 0;; ++fmt) {
542					n = n * 10 + ch - '0';
543					ch = *fmt;
544					if (ch < '0' || ch > '9')
545						break;
546				}
547			if (dot)
548				dwidth = n;
549			else
550				width = n;
551			goto reswitch;
552		case 'b':
553			ul = va_arg(ap, int);
554			p = va_arg(ap, char *);
555			for (q = ksprintn(nbuf, ul, *p++, NULL); *q;)
556				PCHAR(*q--);
557
558			if (!ul)
559				break;
560
561			for (tmp = 0; *p;) {
562				n = *p++;
563				if (ul & (1 << (n - 1))) {
564					PCHAR(tmp ? ',' : '<');
565					for (; (n = *p) > ' '; ++p)
566						PCHAR(n);
567					tmp = 1;
568				} else
569					for (; *p > ' '; ++p)
570						continue;
571			}
572			if (tmp)
573				PCHAR('>');
574			break;
575		case 'c':
576			PCHAR(va_arg(ap, int));
577			break;
578		case 'D':
579			up = va_arg(ap, u_char *);
580			p = va_arg(ap, char *);
581			if (!width)
582				width = 16;
583			while(width--) {
584				PCHAR(hex2ascii(*up >> 4));
585				PCHAR(hex2ascii(*up & 0x0f));
586				up++;
587				if (width)
588					for (q=p;*q;q++)
589						PCHAR(*q);
590			}
591			break;
592		case 'd':
593			if (qflag)
594				uq = va_arg(ap, quad_t);
595			else if (lflag)
596				ul = va_arg(ap, long);
597			else
598				ul = va_arg(ap, int);
599			sign = 1;
600			base = 10;
601			goto number;
602		case 'l':
603			if (lflag) {
604				lflag = 0;
605				qflag = 1;
606			} else
607				lflag = 1;
608			goto reswitch;
609		case 'o':
610			if (qflag)
611				uq = va_arg(ap, u_quad_t);
612			else if (lflag)
613				ul = va_arg(ap, u_long);
614			else
615				ul = va_arg(ap, u_int);
616			base = 8;
617			goto nosign;
618		case 'p':
619			ul = (uintptr_t)va_arg(ap, void *);
620			base = 16;
621			sharpflag = (width == 0);
622			goto nosign;
623		case 'q':
624			qflag = 1;
625			goto reswitch;
626		case 'n':
627		case 'r':
628			if (qflag)
629				uq = va_arg(ap, u_quad_t);
630			else if (lflag)
631				ul = va_arg(ap, u_long);
632			else
633				ul = sign ?
634				    (u_long)va_arg(ap, int) : va_arg(ap, u_int);
635			base = radix;
636			goto number;
637		case 's':
638			p = va_arg(ap, char *);
639			if (p == NULL)
640				p = "(null)";
641			if (!dot)
642				n = strlen (p);
643			else
644				for (n = 0; n < dwidth && p[n]; n++)
645					continue;
646
647			width -= n;
648
649			if (!ladjust && width > 0)
650				while (width--)
651					PCHAR(padc);
652			while (n--)
653				PCHAR(*p++);
654			if (ladjust && width > 0)
655				while (width--)
656					PCHAR(padc);
657			break;
658		case 'u':
659			if (qflag)
660				uq = va_arg(ap, u_quad_t);
661			else if (lflag)
662				ul = va_arg(ap, u_long);
663			else
664				ul = va_arg(ap, u_int);
665			base = 10;
666			goto nosign;
667		case 'x':
668			if (qflag)
669				uq = va_arg(ap, u_quad_t);
670			else if (lflag)
671				ul = va_arg(ap, u_long);
672			else
673				ul = va_arg(ap, u_int);
674			base = 16;
675			goto nosign;
676		case 'z':
677			if (qflag)
678				uq = va_arg(ap, u_quad_t);
679			else if (lflag)
680				ul = va_arg(ap, u_long);
681			else
682				ul = sign ?
683				    (u_long)va_arg(ap, int) : va_arg(ap, u_int);
684			base = 16;
685			goto number;
686nosign:			sign = 0;
687number:
688			if (qflag) {
689				if (sign && (quad_t)uq < 0) {
690					neg = 1;
691					uq = -(quad_t)uq;
692				}
693				p = ksprintqn(nbuf, uq, base, &tmp);
694			} else {
695				if (sign && (long)ul < 0) {
696					neg = 1;
697					ul = -(long)ul;
698				}
699				p = ksprintn(nbuf, ul, base, &tmp);
700			}
701			if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
702				if (base == 8)
703					tmp++;
704				else if (base == 16)
705					tmp += 2;
706			}
707			if (neg)
708				tmp++;
709
710			if (!ladjust && width && (width -= tmp) > 0)
711				while (width--)
712					PCHAR(padc);
713			if (neg)
714				PCHAR('-');
715			if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
716				if (base == 8) {
717					PCHAR('0');
718				} else if (base == 16) {
719					PCHAR('0');
720					PCHAR('x');
721				}
722			}
723
724			while (*p)
725				PCHAR(*p--);
726
727			if (ladjust && width && (width -= tmp) > 0)
728				while (width--)
729					PCHAR(padc);
730
731			break;
732		default:
733			PCHAR('%');
734			if (lflag)
735				PCHAR('l');
736			PCHAR(ch);
737			break;
738		}
739	}
740#undef PCHAR
741}
742
743/*
744 * Put character in log buffer.
745 */
746static void
747msglogchar(int c, void *dummyarg)
748{
749	struct msgbuf *mbp;
750
751	if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
752		mbp = msgbufp;
753		mbp->msg_ptr[mbp->msg_bufx++] = c;
754		if (mbp->msg_bufx >= mbp->msg_size)
755			mbp->msg_bufx = 0;
756		/* If the buffer is full, keep the most recent data. */
757		if (mbp->msg_bufr == mbp->msg_bufx) {
758			if (++mbp->msg_bufr >= mbp->msg_size)
759				mbp->msg_bufr = 0;
760		}
761	}
762}
763
764static void
765msgbufcopy(struct msgbuf *oldp)
766{
767	int pos;
768
769	pos = oldp->msg_bufr;
770	while (pos != oldp->msg_bufx) {
771		msglogchar(oldp->msg_ptr[pos], NULL);
772		if (++pos >= oldp->msg_size)
773			pos = 0;
774	}
775}
776
777void
778msgbufinit(void *ptr, size_t size)
779{
780	char *cp;
781	static struct msgbuf *oldp = NULL;
782
783	cp = (char *)ptr;
784	msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp));
785	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) {
786		bzero(cp, size);
787		msgbufp->msg_magic = MSG_MAGIC;
788		msgbufp->msg_size = (char *)msgbufp - cp;
789		msgbufp->msg_ptr = cp;
790	}
791	if (msgbufmapped && oldp != msgbufp)
792		msgbufcopy(oldp);
793	msgbufmapped = 1;
794	oldp = msgbufp;
795}
796
797#include "opt_ddb.h"
798#ifdef DDB
799#include <ddb/ddb.h>
800
801DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
802{
803	int i, j;
804
805	if (!msgbufmapped) {
806		db_printf("msgbuf not mapped yet\n");
807		return;
808	}
809	db_printf("msgbufp = %p\n", msgbufp);
810	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
811	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
812	    msgbufp->msg_bufx, msgbufp->msg_ptr);
813	for (i = 0; i < msgbufp->msg_size; i++) {
814		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
815		db_printf("%c", msgbufp->msg_ptr[j]);
816	}
817	db_printf("\n");
818}
819
820#endif /* DDB */
821