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