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