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