hexdump.c revision 131931
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 * 4. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/kern/subr_prf.c 131931 2004-07-10 21:43:23Z marcel $");
39
40#include "opt_ddb.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/lock.h>
45#include <sys/kdb.h>
46#include <sys/mutex.h>
47#include <sys/sx.h>
48#include <sys/kernel.h>
49#include <sys/msgbuf.h>
50#include <sys/malloc.h>
51#include <sys/proc.h>
52#include <sys/stddef.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#ifdef DDB
60#include <ddb/ddb.h>
61#endif
62
63/*
64 * Note that stdarg.h and the ANSI style va_start macro is used for both
65 * ANSI and traditional C compilers.
66 */
67#include <machine/stdarg.h>
68
69#define TOCONS	0x01
70#define TOTTY	0x02
71#define TOLOG	0x04
72
73/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
74#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
75
76struct putchar_arg {
77	int	flags;
78	int	pri;
79	struct	tty *tty;
80};
81
82struct snprintf_arg {
83	char	*str;
84	size_t	remain;
85};
86
87extern	int log_open;
88
89static void  msglogchar(int c, int pri);
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, "Duplicate console output to the syslog.");
102
103static int	always_console_output = 0;
104TUNABLE_INT("kern.always_console_output", &always_console_output);
105SYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RW,
106    &always_console_output, 0, "Always output to console despite TIOCCONS.");
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;
164	va_list ap;
165	struct putchar_arg pca;
166	struct session *sess = NULL;
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 = p->p_session;
174			SESS_LOCK(sess);
175			PROC_UNLOCK(p);
176			SESSHOLD(sess);
177			tp = sess->s_ttyp;
178			SESS_UNLOCK(sess);
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	kvprintf(fmt, putchar, &pca, 10, ap);
191	va_end(ap);
192	if (sess != NULL) {
193		SESS_LOCK(sess);
194		SESSRELE(sess);
195		SESS_UNLOCK(sess);
196	}
197	msgbuftrigger = 1;
198}
199
200/*
201 * Ttyprintf displays a message on a tty; it should be used only by
202 * the tty driver, or anything that knows the underlying tty will not
203 * be revoke(2)'d away.  Other callers should use tprintf.
204 */
205int
206ttyprintf(struct tty *tp, const char *fmt, ...)
207{
208	va_list ap;
209	struct putchar_arg pca;
210	int retval;
211
212	va_start(ap, fmt);
213	pca.tty = tp;
214	pca.flags = TOTTY;
215	retval = kvprintf(fmt, putchar, &pca, 10, ap);
216	va_end(ap);
217	return (retval);
218}
219
220/*
221 * Log writes to the log buffer, and guarantees not to sleep (so can be
222 * called by interrupt routines).  If there is no process reading the
223 * log yet, it writes to the console also.
224 */
225void
226log(int level, const char *fmt, ...)
227{
228	va_list ap;
229	struct putchar_arg pca;
230
231	pca.tty = NULL;
232	pca.pri = level;
233	pca.flags = log_open ? TOLOG : TOCONS;
234
235	va_start(ap, fmt);
236	kvprintf(fmt, putchar, &pca, 10, ap);
237	va_end(ap);
238
239	msgbuftrigger = 1;
240}
241
242#define CONSCHUNK 128
243
244void
245log_console(struct uio *uio)
246{
247	int c, i, error, nl;
248	char *consbuffer;
249	int pri;
250
251	if (!log_console_output)
252		return;
253
254	pri = LOG_INFO | LOG_CONSOLE;
255	uio = cloneuio(uio);
256	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
257
258	nl = 0;
259	while (uio->uio_resid > 0) {
260		c = imin(uio->uio_resid, CONSCHUNK);
261		error = uiomove(consbuffer, c, uio);
262		if (error != 0)
263			break;
264		for (i = 0; i < c; i++) {
265			msglogchar(consbuffer[i], pri);
266			if (consbuffer[i] == '\n')
267				nl = 1;
268			else
269				nl = 0;
270		}
271	}
272	if (!nl)
273		msglogchar('\n', pri);
274	msgbuftrigger = 1;
275	free(uio, M_IOV);
276	free(consbuffer, M_TEMP);
277	return;
278}
279
280int
281printf(const char *fmt, ...)
282{
283	va_list ap;
284	int savintr;
285	struct putchar_arg pca;
286	int retval;
287
288	savintr = consintr;		/* disable interrupts */
289	consintr = 0;
290	va_start(ap, fmt);
291	pca.tty = NULL;
292	pca.flags = TOCONS | TOLOG;
293	pca.pri = -1;
294	retval = kvprintf(fmt, putchar, &pca, 10, ap);
295	va_end(ap);
296	if (!panicstr)
297		msgbuftrigger = 1;
298	consintr = savintr;		/* reenable interrupts */
299	return (retval);
300}
301
302int
303vprintf(const char *fmt, va_list ap)
304{
305	int savintr;
306	struct putchar_arg pca;
307	int retval;
308
309	savintr = consintr;		/* disable interrupts */
310	consintr = 0;
311	pca.tty = NULL;
312	pca.flags = TOCONS | TOLOG;
313	pca.pri = -1;
314	retval = kvprintf(fmt, putchar, &pca, 10, ap);
315	if (!panicstr)
316		msgbuftrigger = 1;
317	consintr = savintr;		/* reenable interrupts */
318	return (retval);
319}
320
321/*
322 * Print a character on console or users terminal.  If destination is
323 * the console then the last bunch of characters are saved in msgbuf for
324 * inspection later.
325 */
326static void
327putchar(int c, void *arg)
328{
329	struct putchar_arg *ap = (struct putchar_arg*) arg;
330	struct tty *tp = ap->tty;
331	int consdirect, flags = ap->flags;
332
333	consdirect = ((flags & TOCONS) && constty == NULL);
334	/* Don't use the tty code after a panic or while in ddb. */
335	if (panicstr)
336		consdirect = 1;
337	if (kdb_active)
338		consdirect = 1;
339	if (consdirect) {
340		if (c != '\0')
341			cnputc(c);
342	} else {
343		if ((flags & TOTTY) && tp != NULL)
344			tputchar(c, tp);
345		if (flags & TOCONS) {
346			if (constty != NULL)
347				msgbuf_addchar(&consmsgbuf, c);
348			if (always_console_output && c != '\0')
349				cnputc(c);
350		}
351	}
352	if ((flags & TOLOG))
353		msglogchar(c, ap->pri);
354}
355
356/*
357 * Scaled down version of sprintf(3).
358 */
359int
360sprintf(char *buf, const char *cfmt, ...)
361{
362	int retval;
363	va_list ap;
364
365	va_start(ap, cfmt);
366	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
367	buf[retval] = '\0';
368	va_end(ap);
369	return (retval);
370}
371
372/*
373 * Scaled down version of vsprintf(3).
374 */
375int
376vsprintf(char *buf, const char *cfmt, va_list ap)
377{
378	int retval;
379
380	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
381	buf[retval] = '\0';
382	return (retval);
383}
384
385/*
386 * Scaled down version of snprintf(3).
387 */
388int
389snprintf(char *str, size_t size, const char *format, ...)
390{
391	int retval;
392	va_list ap;
393
394	va_start(ap, format);
395	retval = vsnprintf(str, size, format, ap);
396	va_end(ap);
397	return(retval);
398}
399
400/*
401 * Scaled down version of vsnprintf(3).
402 */
403int
404vsnprintf(char *str, size_t size, const char *format, va_list ap)
405{
406	struct snprintf_arg info;
407	int retval;
408
409	info.str = str;
410	info.remain = size;
411	retval = kvprintf(format, snprintf_func, &info, 10, ap);
412	if (info.remain >= 1)
413		*info.str++ = '\0';
414	return (retval);
415}
416
417/*
418 * Kernel version which takes radix argument vsnprintf(3).
419 */
420int
421vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
422{
423	struct snprintf_arg info;
424	int retval;
425
426	info.str = str;
427	info.remain = size;
428	retval = kvprintf(format, snprintf_func, &info, radix, ap);
429	if (info.remain >= 1)
430		*info.str++ = '\0';
431	return (retval);
432}
433
434static void
435snprintf_func(int ch, void *arg)
436{
437	struct snprintf_arg *const info = arg;
438
439	if (info->remain >= 2) {
440		*info->str++ = ch;
441		info->remain--;
442	}
443}
444
445/*
446 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
447 * order; return an optional length and a pointer to the last character
448 * written in the buffer (i.e., the first character of the string).
449 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
450 */
451static char *
452ksprintn(char *nbuf, uintmax_t num, int base, int *lenp)
453{
454	char *p;
455
456	p = nbuf;
457	*p = '\0';
458	do {
459		*++p = hex2ascii(num % base);
460	} while (num /= base);
461	if (lenp)
462		*lenp = p - nbuf;
463	return (p);
464}
465
466/*
467 * Scaled down version of printf(3).
468 *
469 * Two additional formats:
470 *
471 * The format %b is supported to decode error registers.
472 * Its usage is:
473 *
474 *	printf("reg=%b\n", regval, "<base><arg>*");
475 *
476 * where <base> is the output base expressed as a control character, e.g.
477 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
478 * the first of which gives the bit number to be inspected (origin 1), and
479 * the next characters (up to a control character, i.e. a character <= 32),
480 * give the name of the register.  Thus:
481 *
482 *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
483 *
484 * would produce output:
485 *
486 *	reg=3<BITTWO,BITONE>
487 *
488 * XXX:  %D  -- Hexdump, takes pointer and separator string:
489 *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
490 *		("%*D", len, ptr, " " -> XX XX XX XX ...
491 */
492int
493kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
494{
495#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
496	char nbuf[MAXNBUF];
497	char *d;
498	const char *p, *percent, *q;
499	u_char *up;
500	int ch, n;
501	uintmax_t num;
502	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
503	int cflag, hflag, jflag, tflag, zflag;
504	int dwidth;
505	char padc;
506	int retval = 0;
507
508	num = 0;
509	if (!func)
510		d = (char *) arg;
511	else
512		d = NULL;
513
514	if (fmt == NULL)
515		fmt = "(fmt null)\n";
516
517	if (radix < 2 || radix > 36)
518		radix = 10;
519
520	for (;;) {
521		padc = ' ';
522		width = 0;
523		while ((ch = (u_char)*fmt++) != '%') {
524			if (ch == '\0')
525				return (retval);
526			PCHAR(ch);
527		}
528		percent = fmt - 1;
529		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
530		sign = 0; dot = 0; dwidth = 0;
531		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
532reswitch:	switch (ch = (u_char)*fmt++) {
533		case '.':
534			dot = 1;
535			goto reswitch;
536		case '#':
537			sharpflag = 1;
538			goto reswitch;
539		case '+':
540			sign = 1;
541			goto reswitch;
542		case '-':
543			ladjust = 1;
544			goto reswitch;
545		case '%':
546			PCHAR(ch);
547			break;
548		case '*':
549			if (!dot) {
550				width = va_arg(ap, int);
551				if (width < 0) {
552					ladjust = !ladjust;
553					width = -width;
554				}
555			} else {
556				dwidth = va_arg(ap, int);
557			}
558			goto reswitch;
559		case '0':
560			if (!dot) {
561				padc = '0';
562				goto reswitch;
563			}
564		case '1': case '2': case '3': case '4':
565		case '5': case '6': case '7': case '8': case '9':
566				for (n = 0;; ++fmt) {
567					n = n * 10 + ch - '0';
568					ch = *fmt;
569					if (ch < '0' || ch > '9')
570						break;
571				}
572			if (dot)
573				dwidth = n;
574			else
575				width = n;
576			goto reswitch;
577		case 'b':
578			num = (u_int)va_arg(ap, int);
579			p = va_arg(ap, char *);
580			for (q = ksprintn(nbuf, num, *p++, NULL); *q;)
581				PCHAR(*q--);
582
583			if (num == 0)
584				break;
585
586			for (tmp = 0; *p;) {
587				n = *p++;
588				if (num & (1 << (n - 1))) {
589					PCHAR(tmp ? ',' : '<');
590					for (; (n = *p) > ' '; ++p)
591						PCHAR(n);
592					tmp = 1;
593				} else
594					for (; *p > ' '; ++p)
595						continue;
596			}
597			if (tmp)
598				PCHAR('>');
599			break;
600		case 'c':
601			PCHAR(va_arg(ap, int));
602			break;
603		case 'D':
604			up = va_arg(ap, u_char *);
605			p = va_arg(ap, char *);
606			if (!width)
607				width = 16;
608			while(width--) {
609				PCHAR(hex2ascii(*up >> 4));
610				PCHAR(hex2ascii(*up & 0x0f));
611				up++;
612				if (width)
613					for (q=p;*q;q++)
614						PCHAR(*q);
615			}
616			break;
617		case 'd':
618		case 'i':
619			base = 10;
620			sign = 1;
621			goto handle_sign;
622		case 'h':
623			if (hflag) {
624				hflag = 0;
625				cflag = 1;
626			} else
627				hflag = 1;
628			goto reswitch;
629		case 'j':
630			jflag = 1;
631			goto reswitch;
632		case 'l':
633			if (lflag) {
634				lflag = 0;
635				qflag = 1;
636			} else
637				lflag = 1;
638			goto reswitch;
639		case 'n':
640			if (jflag)
641				*(va_arg(ap, intmax_t *)) = retval;
642			else if (qflag)
643				*(va_arg(ap, quad_t *)) = retval;
644			else if (lflag)
645				*(va_arg(ap, long *)) = retval;
646			else if (zflag)
647				*(va_arg(ap, size_t *)) = retval;
648			else if (hflag)
649				*(va_arg(ap, short *)) = retval;
650			else if (cflag)
651				*(va_arg(ap, char *)) = retval;
652			else
653				*(va_arg(ap, int *)) = retval;
654			break;
655		case 'o':
656			base = 8;
657			goto handle_nosign;
658		case 'p':
659			base = 16;
660			sharpflag = (width == 0);
661			sign = 0;
662			num = (uintptr_t)va_arg(ap, void *);
663			goto number;
664		case 'q':
665			qflag = 1;
666			goto reswitch;
667		case 'r':
668			base = radix;
669			if (sign)
670				goto handle_sign;
671			goto handle_nosign;
672		case 's':
673			p = va_arg(ap, char *);
674			if (p == NULL)
675				p = "(null)";
676			if (!dot)
677				n = strlen (p);
678			else
679				for (n = 0; n < dwidth && p[n]; n++)
680					continue;
681
682			width -= n;
683
684			if (!ladjust && width > 0)
685				while (width--)
686					PCHAR(padc);
687			while (n--)
688				PCHAR(*p++);
689			if (ladjust && width > 0)
690				while (width--)
691					PCHAR(padc);
692			break;
693		case 't':
694			tflag = 1;
695			goto reswitch;
696		case 'u':
697			base = 10;
698			goto handle_nosign;
699		case 'x':
700		case 'X':
701			base = 16;
702			goto handle_nosign;
703		case 'y':
704			base = 16;
705			sign = 1;
706			goto handle_sign;
707		case 'z':
708			zflag = 1;
709			goto reswitch;
710handle_nosign:
711			sign = 0;
712			if (jflag)
713				num = va_arg(ap, uintmax_t);
714			else if (qflag)
715				num = va_arg(ap, u_quad_t);
716			else if (tflag)
717				num = va_arg(ap, ptrdiff_t);
718			else if (lflag)
719				num = va_arg(ap, u_long);
720			else if (zflag)
721				num = va_arg(ap, size_t);
722			else if (hflag)
723				num = (u_short)va_arg(ap, int);
724			else if (cflag)
725				num = (u_char)va_arg(ap, int);
726			else
727				num = va_arg(ap, u_int);
728			goto number;
729handle_sign:
730			if (jflag)
731				num = va_arg(ap, intmax_t);
732			else if (qflag)
733				num = va_arg(ap, quad_t);
734			else if (tflag)
735				num = va_arg(ap, ptrdiff_t);
736			else if (lflag)
737				num = va_arg(ap, long);
738			else if (zflag)
739				num = va_arg(ap, size_t);
740			else if (hflag)
741				num = (short)va_arg(ap, int);
742			else if (cflag)
743				num = (char)va_arg(ap, int);
744			else
745				num = va_arg(ap, int);
746number:
747			if (sign && (intmax_t)num < 0) {
748				neg = 1;
749				num = -(intmax_t)num;
750			}
751			p = ksprintn(nbuf, num, base, &tmp);
752			if (sharpflag && num != 0) {
753				if (base == 8)
754					tmp++;
755				else if (base == 16)
756					tmp += 2;
757			}
758			if (neg)
759				tmp++;
760
761			if (!ladjust && width && (width -= tmp) > 0)
762				while (width--)
763					PCHAR(padc);
764			if (neg)
765				PCHAR('-');
766			if (sharpflag && num != 0) {
767				if (base == 8) {
768					PCHAR('0');
769				} else if (base == 16) {
770					PCHAR('0');
771					PCHAR('x');
772				}
773			}
774
775			while (*p)
776				PCHAR(*p--);
777
778			if (ladjust && width && (width -= tmp) > 0)
779				while (width--)
780					PCHAR(padc);
781
782			break;
783		default:
784			while (percent < fmt)
785				PCHAR(*percent++);
786			break;
787		}
788	}
789#undef PCHAR
790}
791
792/*
793 * Put character in log buffer with a particular priority.
794 */
795static void
796msglogchar(int c, int pri)
797{
798	static int lastpri = -1;
799	static int dangling;
800	char nbuf[MAXNBUF];
801	char *p;
802
803	if (!msgbufmapped)
804		return;
805	if (c == '\0' || c == '\r')
806		return;
807	if (pri != -1 && pri != lastpri) {
808		if (dangling) {
809			msgbuf_addchar(msgbufp, '\n');
810			dangling = 0;
811		}
812		msgbuf_addchar(msgbufp, '<');
813		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
814			msgbuf_addchar(msgbufp, *p--);
815		msgbuf_addchar(msgbufp, '>');
816		lastpri = pri;
817	}
818	msgbuf_addchar(msgbufp, c);
819	if (c == '\n') {
820		dangling = 0;
821		lastpri = -1;
822	} else {
823		dangling = 1;
824	}
825}
826
827void
828msgbufinit(void *ptr, int size)
829{
830	char *cp;
831	static struct msgbuf *oldp = NULL;
832
833	size -= sizeof(*msgbufp);
834	cp = (char *)ptr;
835	msgbufp = (struct msgbuf *)(cp + size);
836	msgbuf_reinit(msgbufp, cp, size);
837	if (msgbufmapped && oldp != msgbufp)
838		msgbuf_copy(oldp, msgbufp);
839	msgbufmapped = 1;
840	oldp = msgbufp;
841}
842
843SYSCTL_DECL(_security_bsd);
844
845static int unprivileged_read_msgbuf = 1;
846SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
847    CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
848    "Unprivileged processes may read the kernel message buffer");
849
850/* Sysctls for accessing/clearing the msgbuf */
851static int
852sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
853{
854	char buf[128];
855	u_int seq;
856	int error, len;
857
858	if (!unprivileged_read_msgbuf) {
859		error = suser(req->td);
860		if (error)
861			return (error);
862	}
863
864	/* Read the whole buffer, one chunk at a time. */
865	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
866	while ((len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq)) > 0) {
867		error = sysctl_handle_opaque(oidp, buf, len, req);
868		if (error)
869			return (error);
870	}
871	return (0);
872}
873
874SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
875    0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
876
877static int msgbuf_clearflag;
878
879static int
880sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
881{
882	int error;
883	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
884	if (!error && req->newptr) {
885		msgbuf_clear(msgbufp);
886		msgbuf_clearflag = 0;
887	}
888	return (error);
889}
890
891SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
892    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clearflag, 0,
893    sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
894
895#ifdef DDB
896
897DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
898{
899	int i, j;
900
901	if (!msgbufmapped) {
902		db_printf("msgbuf not mapped yet\n");
903		return;
904	}
905	db_printf("msgbufp = %p\n", msgbufp);
906	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
907	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
908	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
909	for (i = 0; i < msgbufp->msg_size; i++) {
910		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
911		db_printf("%c", msgbufp->msg_ptr[j]);
912	}
913	db_printf("\n");
914}
915
916#endif /* DDB */
917
918void
919hexdump(void *ptr, int length, const char *hdr, int flags)
920{
921	int i, j, k;
922	int cols;
923	unsigned char *cp;
924	char delim;
925
926	if ((flags & HD_DELIM_MASK) != 0)
927		delim = (flags & HD_DELIM_MASK) >> 8;
928	else
929		delim = ' ';
930
931	if ((flags & HD_COLUMN_MASK) != 0)
932		cols = flags & HD_COLUMN_MASK;
933	else
934		cols = 16;
935
936	cp = ptr;
937	for (i = 0; i < length; i+= cols) {
938		if (hdr != NULL)
939			printf("%s", hdr);
940
941		if ((flags & HD_OMIT_COUNT) == 0)
942			printf("%04x  ", i);
943
944		if ((flags & HD_OMIT_HEX) == 0) {
945			for (j = 0; j < cols; j++) {
946				k = i + j;
947				if (k < length)
948					printf("%c%02x", delim, cp[k]);
949				else
950					printf("   ");
951			}
952		}
953
954		if ((flags & HD_OMIT_CHARS) == 0) {
955			printf("  |");
956			for (j = 0; j < cols; j++) {
957				k = i + j;
958				if (k >= length)
959					printf(" ");
960				else if (cp[k] >= ' ' && cp[k] <= '~')
961					printf("%c", cp[k]);
962				else
963					printf(".");
964			}
965			printf("|\n");
966		}
967	}
968}
969
970