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