hexdump.c revision 116660
197049Speter/*-
2184989Srafan * Copyright (c) 1986, 1988, 1991, 1993
397049Speter *	The Regents of the University of California.  All rights reserved.
497049Speter * (c) UNIX System Laboratories, Inc.
597049Speter * All or some portions of this file are derived from material licensed
697049Speter * to the University of California by American Telephone and Telegraph
797049Speter * Co. or Unix System Laboratories, Inc. and are reproduced herein with
897049Speter * the permission of UNIX System Laboratories, Inc.
997049Speter *
1097049Speter * Redistribution and use in source and binary forms, with or without
1197049Speter * modification, are permitted provided that the following conditions
1297049Speter * are met:
1397049Speter * 1. Redistributions of source code must retain the above copyright
1497049Speter *    notice, this list of conditions and the following disclaimer.
1597049Speter * 2. Redistributions in binary form must reproduce the above copyright
1697049Speter *    notice, this list of conditions and the following disclaimer in the
1797049Speter *    documentation and/or other materials provided with the distribution.
1897049Speter * 3. All advertising materials mentioning features or use of this software
1997049Speter *    must display the following acknowledgement:
2097049Speter *	This product includes software developed by the University of
2197049Speter *	California, Berkeley and its contributors.
2297049Speter * 4. Neither the name of the University nor the names of its contributors
2397049Speter *    may be used to endorse or promote products derived from this software
2497049Speter *    without specific prior written permission.
2597049Speter *
2697049Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2797049Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2897049Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2997049Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30184989Srafan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3197049Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3297049Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3397049Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3497049Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3597049Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3697049Speter * SUCH DAMAGE.
3797049Speter *
3897049Speter *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
3997049Speter */
4097049Speter
4197049Speter#include <sys/cdefs.h>
4297049Speter__FBSDID("$FreeBSD: head/sys/kern/subr_prf.c 116660 2003-06-22 02:18:31Z iedowse $");
4397049Speter
4497049Speter#include "opt_ddb.h"
4597049Speter
4697049Speter#include <sys/param.h>
4797049Speter#include <sys/systm.h>
4897049Speter#include <sys/lock.h>
4997049Speter#include <sys/mutex.h>
5097049Speter#include <sys/sx.h>
5197049Speter#include <sys/kernel.h>
5297049Speter#include <sys/msgbuf.h>
5397049Speter#include <sys/malloc.h>
5497049Speter#include <sys/proc.h>
5597049Speter#include <sys/stddef.h>
5697049Speter#include <sys/sysctl.h>
5797049Speter#include <sys/tty.h>
5897049Speter#include <sys/syslog.h>
5997049Speter#include <sys/cons.h>
6097049Speter#include <sys/uio.h>
6197049Speter
6297049Speter#ifdef DDB
6397049Speter#include <ddb/ddb.h>
6497049Speter#endif
6597049Speter
6697049Speter/*
6797049Speter * Note that stdarg.h and the ANSI style va_start macro is used for both
6897049Speter * ANSI and traditional C compilers.
6997049Speter */
7097049Speter#include <machine/stdarg.h>
7197049Speter
7297049Speter#define TOCONS	0x01
7397049Speter#define TOTTY	0x02
7497049Speter#define TOLOG	0x04
7597049Speter
7697049Speter/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
7797049Speter#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
7897049Speter
79166124Srafanstruct putchar_arg {
80166124Srafan	int	flags;
81166124Srafan	int	pri;
82166124Srafan	struct	tty *tty;
83166124Srafan};
84166124Srafan
8597049Speterstruct snprintf_arg {
8697049Speter	char	*str;
8797049Speter	size_t	remain;
8897049Speter};
8997049Speter
9097049Speterextern	int log_open;
9197049Speter
9297049Speterstruct	tty *constty;			/* pointer to console "window" tty */
9397049Speter
9497049Speterstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
9597049Speterstatic void  msglogchar(int c, int pri);
9697049Speterstatic void  putchar(int ch, void *arg);
9797049Speterstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
9897049Speterstatic void  snprintf_func(int ch, void *arg);
9997049Speter
10097049Speterstatic int consintr = 1;		/* Ok to handle console interrupts? */
10197049Speterstatic int msgbufmapped;		/* Set when safe to use msgbuf */
10297049Speterint msgbuftrigger;
10397049Speter
10497049Speterstatic int      log_console_output = 1;
10597049SpeterTUNABLE_INT("kern.log_console_output", &log_console_output);
10697049SpeterSYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW,
10797049Speter    &log_console_output, 0, "");
108166124Srafan
10997049Speter/*
11097049Speter * Warn that a system table is full.
11197049Speter */
11297049Spetervoid
11397049Spetertablefull(const char *tab)
11497049Speter{
115166124Srafan
11697049Speter	log(LOG_ERR, "%s: table is full\n", tab);
11797049Speter}
11897049Speter
11997049Speter/*
12097049Speter * Uprintf prints to the controlling terminal for the current process.
12197049Speter * It may block if the tty queue is overfull.  No message is printed if
12297049Speter * the queue does not clear in a reasonable time.
12397049Speter */
12497049Speterint
12597049Speteruprintf(const char *fmt, ...)
12697049Speter{
127166124Srafan	struct thread *td = curthread;
12897049Speter	struct proc *p = td->td_proc;
12997049Speter	va_list ap;
13097049Speter	struct putchar_arg pca;
13197049Speter	int retval;
13297049Speter
13397049Speter	if (td == NULL || td == PCPU_GET(idlethread))
13497049Speter		return (0);
13597049Speter
13697049Speter	p = td->td_proc;
13797049Speter	PROC_LOCK(p);
13897049Speter	if ((p->p_flag & P_CONTROLT) == 0) {
13997049Speter		PROC_UNLOCK(p);
14097049Speter		return (0);
14197049Speter	}
14297049Speter	SESS_LOCK(p->p_session);
14397049Speter	pca.tty = p->p_session->s_ttyp;
14497049Speter	SESS_UNLOCK(p->p_session);
14597049Speter	PROC_UNLOCK(p);
14697049Speter	if (pca.tty == NULL)
14797049Speter		return (0);
14897049Speter	pca.flags = TOTTY;
14997049Speter	va_start(ap, fmt);
15097049Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
15197049Speter	va_end(ap);
15297049Speter
15397049Speter	return (retval);
15497049Speter}
15597049Speter
15697049Speter/*
15797049Speter * tprintf prints on the controlling terminal associated
15897049Speter * with the given session, possibly to the log as well.
15997049Speter */
16097049Spetervoid
16197049Spetertprintf(struct proc *p, int pri, const char *fmt, ...)
16297049Speter{
16397049Speter	struct tty *tp = NULL;
16497049Speter	int flags = 0;
16597049Speter	va_list ap;
16697049Speter	struct putchar_arg pca;
167166124Srafan	struct session *sess = NULL;
16897049Speter
16997049Speter	if (pri != -1)
17097049Speter		flags |= TOLOG;
17197049Speter	if (p != NULL) {
17297049Speter		PROC_LOCK(p);
17397049Speter		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
17497049Speter			sess = p->p_session;
17597049Speter			SESS_LOCK(sess);
17697049Speter			PROC_UNLOCK(p);
17797049Speter			SESSHOLD(sess);
17897049Speter			tp = sess->s_ttyp;
17997049Speter			SESS_UNLOCK(sess);
18097049Speter			if (ttycheckoutq(tp, 0))
18197049Speter				flags |= TOTTY;
18297049Speter			else
18397049Speter				tp = NULL;
18497049Speter		} else
18597049Speter			PROC_UNLOCK(p);
18697049Speter	}
18797049Speter	pca.pri = pri;
18897049Speter	pca.tty = tp;
18997049Speter	pca.flags = flags;
19097049Speter	va_start(ap, fmt);
19197049Speter	kvprintf(fmt, putchar, &pca, 10, ap);
19297049Speter	va_end(ap);
19397049Speter	if (sess != NULL) {
19497049Speter		SESS_LOCK(sess);
19597049Speter		SESSRELE(sess);
19697049Speter		SESS_UNLOCK(sess);
19797049Speter	}
19897049Speter	msgbuftrigger = 1;
19997049Speter}
20097049Speter
20197049Speter/*
20297049Speter * Ttyprintf displays a message on a tty; it should be used only by
20397049Speter * the tty driver, or anything that knows the underlying tty will not
20497049Speter * be revoke(2)'d away.  Other callers should use tprintf.
20597049Speter */
20697049Speterint
20797049Speterttyprintf(struct tty *tp, const char *fmt, ...)
20897049Speter{
20997049Speter	va_list ap;
21097049Speter	struct putchar_arg pca;
21197049Speter	int retval;
21297049Speter
21397049Speter	va_start(ap, fmt);
21497049Speter	pca.tty = tp;
21597049Speter	pca.flags = TOTTY;
21697049Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
21797049Speter	va_end(ap);
21897049Speter	return (retval);
21997049Speter}
22097049Speter
22197049Speter/*
22297049Speter * Log writes to the log buffer, and guarantees not to sleep (so can be
22397049Speter * called by interrupt routines).  If there is no process reading the
22497049Speter * log yet, it writes to the console also.
22597049Speter */
22697049Spetervoid
22797049Speterlog(int level, const char *fmt, ...)
22897049Speter{
22997049Speter	va_list ap;
23097049Speter	struct putchar_arg pca;
23197049Speter
23297049Speter	pca.tty = NULL;
23397049Speter	pca.pri = level;
234166124Srafan	pca.flags = log_open ? TOLOG : TOCONS;
235166124Srafan
236166124Srafan	va_start(ap, fmt);
237166124Srafan	kvprintf(fmt, putchar, &pca, 10, ap);
23897049Speter	va_end(ap);
23997049Speter
24097049Speter	msgbuftrigger = 1;
24197049Speter}
24297049Speter
24397049Speter#define CONSCHUNK 128
24497049Speter
24597049Spetervoid
24697049Speterlog_console(struct uio *uio)
24797049Speter{
24897049Speter	int c, i, error, iovlen, nl;
24997049Speter	struct uio muio;
25097049Speter	struct iovec *miov = NULL;
25197049Speter	char *consbuffer;
25297049Speter	int pri;
25397049Speter
25497049Speter	if (!log_console_output)
25597049Speter		return;
25697049Speter
25797049Speter	pri = LOG_INFO | LOG_CONSOLE;
25897049Speter	muio = *uio;
25997049Speter	iovlen = uio->uio_iovcnt * sizeof (struct iovec);
26097049Speter	MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
26197049Speter	MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
26297049Speter	bcopy(muio.uio_iov, miov, iovlen);
26397049Speter	muio.uio_iov = miov;
26497049Speter	uio = &muio;
26597049Speter
26697049Speter	nl = 0;
26797049Speter	while (uio->uio_resid > 0) {
26897049Speter		c = imin(uio->uio_resid, CONSCHUNK);
26997049Speter		error = uiomove(consbuffer, c, uio);
27097049Speter		if (error != 0)
27197049Speter			break;
27297049Speter		for (i = 0; i < c; i++) {
27397049Speter			msglogchar(consbuffer[i], pri);
27497049Speter			if (consbuffer[i] == '\n')
27597049Speter				nl = 1;
27697049Speter			else
27797049Speter				nl = 0;
27897049Speter		}
27997049Speter	}
28097049Speter	if (!nl)
28197049Speter		msglogchar('\n', pri);
282166124Srafan	msgbuftrigger = 1;
283166124Srafan	FREE(miov, M_TEMP);
28497049Speter	FREE(consbuffer, M_TEMP);
28597049Speter	return;
28697049Speter}
28797049Speter
28897049Speterint
28997049Speterprintf(const char *fmt, ...)
29097049Speter{
29197049Speter	va_list ap;
29297049Speter	int savintr;
29397049Speter	struct putchar_arg pca;
29497049Speter	int retval;
29597049Speter
29697049Speter	savintr = consintr;		/* disable interrupts */
29797049Speter	consintr = 0;
29897049Speter	va_start(ap, fmt);
29997049Speter	pca.tty = NULL;
30097049Speter	pca.flags = TOCONS | TOLOG;
30197049Speter	pca.pri = -1;
30297049Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
30397049Speter	va_end(ap);
30497049Speter	if (!panicstr)
30597049Speter		msgbuftrigger = 1;
30697049Speter	consintr = savintr;		/* reenable interrupts */
30797049Speter	return (retval);
30897049Speter}
30997049Speter
31097049Speterint
31197049Spetervprintf(const char *fmt, va_list ap)
31297049Speter{
31397049Speter	int savintr;
31497049Speter	struct putchar_arg pca;
31597049Speter	int retval;
31697049Speter
31797049Speter	savintr = consintr;		/* disable interrupts */
31897049Speter	consintr = 0;
31997049Speter	pca.tty = NULL;
32097049Speter	pca.flags = TOCONS | TOLOG;
32197049Speter	pca.pri = -1;
32297049Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
32397049Speter	if (!panicstr)
32497049Speter		msgbuftrigger = 1;
32597049Speter	consintr = savintr;		/* reenable interrupts */
32697049Speter	return (retval);
32797049Speter}
32897049Speter
32997049Speter/*
33097049Speter * Print a character on console or users terminal.  If destination is
33197049Speter * the console then the last bunch of characters are saved in msgbuf for
33297049Speter * inspection later.
33397049Speter */
33497049Speterstatic void
33597049Speterputchar(int c, void *arg)
33697049Speter{
33797049Speter	struct putchar_arg *ap = (struct putchar_arg*) arg;
33897049Speter	int flags = ap->flags;
33997049Speter	struct tty *tp = ap->tty;
34097049Speter	if (panicstr)
34197049Speter		constty = NULL;
34297049Speter	if ((flags & TOCONS) && tp == NULL && constty) {
34397049Speter		tp = constty;
34497049Speter		flags |= TOTTY;
34597049Speter	}
34697049Speter	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
34797049Speter	    (flags & TOCONS) && tp == constty)
34897049Speter		constty = NULL;
34997049Speter	if ((flags & TOLOG))
35097049Speter		msglogchar(c, ap->pri);
35197049Speter	if ((flags & TOCONS) && constty == NULL && c != '\0')
35297049Speter		(*v_putc)(c);
35397049Speter}
35497049Speter
35597049Speter/*
35697049Speter * Scaled down version of sprintf(3).
35797049Speter */
35897049Speterint
35997049Spetersprintf(char *buf, const char *cfmt, ...)
36097049Speter{
36197049Speter	int retval;
36297049Speter	va_list ap;
36397049Speter
36497049Speter	va_start(ap, cfmt);
36597049Speter	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
36697049Speter	buf[retval] = '\0';
36797049Speter	va_end(ap);
36897049Speter	return (retval);
36997049Speter}
37097049Speter
37197049Speter/*
37297049Speter * Scaled down version of vsprintf(3).
37397049Speter */
37497049Speterint
37597049Spetervsprintf(char *buf, const char *cfmt, va_list ap)
37697049Speter{
37797049Speter	int retval;
37897049Speter
37997049Speter	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
38097049Speter	buf[retval] = '\0';
38197049Speter	return (retval);
38297049Speter}
38397049Speter
38497049Speter/*
38597049Speter * Scaled down version of snprintf(3).
38697049Speter */
38797049Speterint
38897049Spetersnprintf(char *str, size_t size, const char *format, ...)
38997049Speter{
39097049Speter	int retval;
39197049Speter	va_list ap;
39297049Speter
39397049Speter	va_start(ap, format);
39497049Speter	retval = vsnprintf(str, size, format, ap);
39597049Speter	va_end(ap);
39697049Speter	return(retval);
39797049Speter}
39897049Speter
39997049Speter/*
40097049Speter * Scaled down version of vsnprintf(3).
40197049Speter */
40297049Speterint
40397049Spetervsnprintf(char *str, size_t size, const char *format, va_list ap)
40497049Speter{
40597049Speter	struct snprintf_arg info;
40697049Speter	int retval;
40797049Speter
40897049Speter	info.str = str;
40997049Speter	info.remain = size;
41097049Speter	retval = kvprintf(format, snprintf_func, &info, 10, ap);
41197049Speter	if (info.remain >= 1)
41297049Speter		*info.str++ = '\0';
41397049Speter	return (retval);
41497049Speter}
41597049Speter
41697049Speter/*
41797049Speter * Kernel version which takes radix argument vsnprintf(3).
41897049Speter */
41997049Speterint
42097049Spetervsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
42197049Speter{
42297049Speter	struct snprintf_arg info;
42397049Speter	int retval;
42497049Speter
42597049Speter	info.str = str;
42697049Speter	info.remain = size;
42797049Speter	retval = kvprintf(format, snprintf_func, &info, radix, ap);
42897049Speter	if (info.remain >= 1)
42997049Speter		*info.str++ = '\0';
43097049Speter	return (retval);
43197049Speter}
43297049Speter
43397049Speterstatic void
43497049Spetersnprintf_func(int ch, void *arg)
43597049Speter{
43697049Speter	struct snprintf_arg *const info = arg;
43797049Speter
43897049Speter	if (info->remain >= 2) {
43997049Speter		*info->str++ = ch;
44097049Speter		info->remain--;
44197049Speter	}
44297049Speter}
44397049Speter
44497049Speter/*
44597049Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
44697049Speter * order; return an optional length and a pointer to the last character
44797049Speter * written in the buffer (i.e., the first character of the string).
44897049Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
44997049Speter */
45097049Speterstatic char *
45197049Speterksprintn(char *nbuf, uintmax_t num, int base, int *lenp)
45297049Speter{
45397049Speter	char *p;
45497049Speter
45597049Speter	p = nbuf;
45697049Speter	*p = '\0';
45797049Speter	do {
45897049Speter		*++p = hex2ascii(num % base);
45997049Speter	} while (num /= base);
46097049Speter	if (lenp)
46197049Speter		*lenp = p - nbuf;
46297049Speter	return (p);
46397049Speter}
46497049Speter
46597049Speter/*
46697049Speter * Scaled down version of printf(3).
46797049Speter *
46897049Speter * Two additional formats:
46997049Speter *
47097049Speter * The format %b is supported to decode error registers.
47197049Speter * Its usage is:
47297049Speter *
47397049Speter *	printf("reg=%b\n", regval, "<base><arg>*");
47497049Speter *
47597049Speter * where <base> is the output base expressed as a control character, e.g.
47697049Speter * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
47797049Speter * the first of which gives the bit number to be inspected (origin 1), and
47897049Speter * the next characters (up to a control character, i.e. a character <= 32),
47997049Speter * give the name of the register.  Thus:
48097049Speter *
48197049Speter *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
48297049Speter *
48397049Speter * would produce output:
48497049Speter *
48597049Speter *	reg=3<BITTWO,BITONE>
48697049Speter *
48797049Speter * XXX:  %D  -- Hexdump, takes pointer and separator string:
48897049Speter *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
48997049Speter *		("%*D", len, ptr, " " -> XX XX XX XX ...
49097049Speter */
49197049Speterint
49297049Speterkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
49397049Speter{
49497049Speter#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
49597049Speter	char nbuf[MAXNBUF];
49697049Speter	char *d;
49797049Speter	const char *p, *percent, *q;
49897049Speter	u_char *up;
49997049Speter	int ch, n;
50097049Speter	uintmax_t num;
50197049Speter	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
50297049Speter	int jflag, tflag, zflag;
50397049Speter	int dwidth;
50497049Speter	char padc;
50597049Speter	int retval = 0;
50697049Speter
50797049Speter	num = 0;
50897049Speter	if (!func)
50997049Speter		d = (char *) arg;
51097049Speter	else
51197049Speter		d = NULL;
51297049Speter
51397049Speter	if (fmt == NULL)
51497049Speter		fmt = "(fmt null)\n";
51597049Speter
51697049Speter	if (radix < 2 || radix > 36)
51797049Speter		radix = 10;
51897049Speter
51997049Speter	for (;;) {
52097049Speter		padc = ' ';
52197049Speter		width = 0;
52297049Speter		while ((ch = (u_char)*fmt++) != '%') {
52397049Speter			if (ch == '\0')
52497049Speter				return (retval);
52597049Speter			PCHAR(ch);
52697049Speter		}
52797049Speter		percent = fmt - 1;
52897049Speter		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
52997049Speter		sign = 0; dot = 0; dwidth = 0;
53097049Speter		jflag = 0; tflag = 0; zflag = 0;
53197049Speterreswitch:	switch (ch = (u_char)*fmt++) {
53297049Speter		case '.':
53397049Speter			dot = 1;
53497049Speter			goto reswitch;
53597049Speter		case '#':
53697049Speter			sharpflag = 1;
53797049Speter			goto reswitch;
53897049Speter		case '+':
53997049Speter			sign = 1;
54097049Speter			goto reswitch;
54197049Speter		case '-':
54297049Speter			ladjust = 1;
54397049Speter			goto reswitch;
54497049Speter		case '%':
54597049Speter			PCHAR(ch);
54697049Speter			break;
54797049Speter		case '*':
54897049Speter			if (!dot) {
54997049Speter				width = va_arg(ap, int);
55097049Speter				if (width < 0) {
55197049Speter					ladjust = !ladjust;
55297049Speter					width = -width;
55397049Speter				}
55497049Speter			} else {
55597049Speter				dwidth = va_arg(ap, int);
55697049Speter			}
55797049Speter			goto reswitch;
55897049Speter		case '0':
55997049Speter			if (!dot) {
56097049Speter				padc = '0';
56197049Speter				goto reswitch;
56297049Speter			}
56397049Speter		case '1': case '2': case '3': case '4':
56497049Speter		case '5': case '6': case '7': case '8': case '9':
56597049Speter				for (n = 0;; ++fmt) {
56697049Speter					n = n * 10 + ch - '0';
56797049Speter					ch = *fmt;
56897049Speter					if (ch < '0' || ch > '9')
56997049Speter						break;
57097049Speter				}
57197049Speter			if (dot)
57297049Speter				dwidth = n;
57397049Speter			else
57497049Speter				width = n;
57597049Speter			goto reswitch;
57697049Speter		case 'b':
57797049Speter			num = (u_int)va_arg(ap, int);
57897049Speter			p = va_arg(ap, char *);
57997049Speter			for (q = ksprintn(nbuf, num, *p++, NULL); *q;)
58097049Speter				PCHAR(*q--);
58197049Speter
58297049Speter			if (num == 0)
58397049Speter				break;
58497049Speter
58597049Speter			for (tmp = 0; *p;) {
58697049Speter				n = *p++;
58797049Speter				if (num & (1 << (n - 1))) {
58897049Speter					PCHAR(tmp ? ',' : '<');
58997049Speter					for (; (n = *p) > ' '; ++p)
59097049Speter						PCHAR(n);
59197049Speter					tmp = 1;
59297049Speter				} else
59397049Speter					for (; *p > ' '; ++p)
59497049Speter						continue;
59597049Speter			}
59697049Speter			if (tmp)
59797049Speter				PCHAR('>');
59897049Speter			break;
59997049Speter		case 'c':
60097049Speter			PCHAR(va_arg(ap, int));
60197049Speter			break;
60297049Speter		case 'D':
60397049Speter			up = va_arg(ap, u_char *);
60497049Speter			p = va_arg(ap, char *);
60597049Speter			if (!width)
60697049Speter				width = 16;
60797049Speter			while(width--) {
60897049Speter				PCHAR(hex2ascii(*up >> 4));
60997049Speter				PCHAR(hex2ascii(*up & 0x0f));
61097049Speter				up++;
61197049Speter				if (width)
61297049Speter					for (q=p;*q;q++)
61397049Speter						PCHAR(*q);
61497049Speter			}
61597049Speter			break;
61697049Speter		case 'd':
61797049Speter		case 'i':
61897049Speter			base = 10;
61997049Speter			sign = 1;
62097049Speter			goto handle_sign;
62197049Speter		case 'j':
62297049Speter			jflag = 1;
62397049Speter			goto reswitch;
62497049Speter		case 'l':
62597049Speter			if (lflag) {
62697049Speter				lflag = 0;
62797049Speter				qflag = 1;
62897049Speter			} else
62997049Speter				lflag = 1;
63097049Speter			goto reswitch;
63197049Speter		case 'n':
63297049Speter			if (jflag)
63397049Speter				*(va_arg(ap, intmax_t *)) = retval;
63497049Speter			else if (qflag)
63597049Speter				*(va_arg(ap, quad_t *)) = retval;
63697049Speter			else if (lflag)
63797049Speter				*(va_arg(ap, long *)) = retval;
63897049Speter			else if (zflag)
63997049Speter				*(va_arg(ap, size_t *)) = retval;
64097049Speter			else
64197049Speter				*(va_arg(ap, int *)) = retval;
64297049Speter			break;
64397049Speter		case 'o':
64497049Speter			base = 8;
64597049Speter			goto handle_nosign;
64697049Speter		case 'p':
64797049Speter			base = 16;
64897049Speter			sharpflag = (width == 0);
64997049Speter			sign = 0;
65097049Speter			num = (uintptr_t)va_arg(ap, void *);
65197049Speter			goto number;
65297049Speter		case 'q':
65397049Speter			qflag = 1;
65497049Speter			goto reswitch;
65597049Speter		case 'r':
65697049Speter			base = radix;
65797049Speter			if (sign)
65897049Speter				goto handle_sign;
65997049Speter			goto handle_nosign;
66097049Speter		case 's':
66197049Speter			p = va_arg(ap, char *);
66297049Speter			if (p == NULL)
66397049Speter				p = "(null)";
66497049Speter			if (!dot)
66597049Speter				n = strlen (p);
66697049Speter			else
66797049Speter				for (n = 0; n < dwidth && p[n]; n++)
66897049Speter					continue;
66997049Speter
67097049Speter			width -= n;
67197049Speter
67297049Speter			if (!ladjust && width > 0)
67397049Speter				while (width--)
67497049Speter					PCHAR(padc);
67597049Speter			while (n--)
67697049Speter				PCHAR(*p++);
67797049Speter			if (ladjust && width > 0)
67897049Speter				while (width--)
67997049Speter					PCHAR(padc);
68097049Speter			break;
68197049Speter		case 't':
68297049Speter			tflag = 1;
68397049Speter			goto reswitch;
68497049Speter		case 'u':
68597049Speter			base = 10;
68697049Speter			goto handle_nosign;
68797049Speter		case 'x':
68897049Speter		case 'X':
68997049Speter			base = 16;
69097049Speter			goto handle_nosign;
69197049Speter		case 'y':
69297049Speter			base = 16;
69397049Speter			sign = 1;
69497049Speter			goto handle_sign;
69597049Speter		case 'z':
69697049Speter			zflag = 1;
69797049Speter			goto reswitch;
69897049Speterhandle_nosign:
69997049Speter			sign = 0;
70097049Speter			if (jflag)
70197049Speter				num = va_arg(ap, uintmax_t);
70297049Speter			else if (qflag)
70397049Speter				num = va_arg(ap, u_quad_t);
70497049Speter			else if (tflag)
70597049Speter				num = va_arg(ap, ptrdiff_t);
70697049Speter			else if (lflag)
70797049Speter				num = va_arg(ap, u_long);
70897049Speter			else if (zflag)
70997049Speter				num = va_arg(ap, size_t);
71097049Speter			else
71197049Speter				num = va_arg(ap, u_int);
71297049Speter			goto number;
71397049Speterhandle_sign:
71497049Speter			if (jflag)
71597049Speter				num = va_arg(ap, intmax_t);
71697049Speter			else if (qflag)
71797049Speter				num = va_arg(ap, quad_t);
71897049Speter			else if (tflag)
71997049Speter				num = va_arg(ap, ptrdiff_t);
72097049Speter			else if (lflag)
72197049Speter				num = va_arg(ap, long);
72297049Speter			else if (zflag)
72397049Speter				num = va_arg(ap, size_t);
72497049Speter			else
72597049Speter				num = va_arg(ap, int);
72697049Speternumber:
72797049Speter			if (sign && (intmax_t)num < 0) {
72897049Speter				neg = 1;
72997049Speter				num = -(intmax_t)num;
73097049Speter			}
73197049Speter			p = ksprintn(nbuf, num, base, &tmp);
73297049Speter			if (sharpflag && num != 0) {
73397049Speter				if (base == 8)
73497049Speter					tmp++;
73597049Speter				else if (base == 16)
73697049Speter					tmp += 2;
73797049Speter			}
73897049Speter			if (neg)
73997049Speter				tmp++;
74097049Speter
74197049Speter			if (!ladjust && width && (width -= tmp) > 0)
74297049Speter				while (width--)
74397049Speter					PCHAR(padc);
74497049Speter			if (neg)
74597049Speter				PCHAR('-');
74697049Speter			if (sharpflag && num != 0) {
74797049Speter				if (base == 8) {
74897049Speter					PCHAR('0');
74997049Speter				} else if (base == 16) {
75097049Speter					PCHAR('0');
75197049Speter					PCHAR('x');
75297049Speter				}
75397049Speter			}
75497049Speter
75597049Speter			while (*p)
75697049Speter				PCHAR(*p--);
75797049Speter
75897049Speter			if (ladjust && width && (width -= tmp) > 0)
75997049Speter				while (width--)
76097049Speter					PCHAR(padc);
76197049Speter
76297049Speter			break;
76397049Speter		default:
76497049Speter			while (percent < fmt)
76597049Speter				PCHAR(*percent++);
76697049Speter			break;
76797049Speter		}
76897049Speter	}
76997049Speter#undef PCHAR
77097049Speter}
77197049Speter
77297049Speter/*
77397049Speter * Put character in log buffer with a particular priority.
77497049Speter */
77597049Speterstatic void
77697049Spetermsglogchar(int c, int pri)
77797049Speter{
77897049Speter	static int lastpri = -1;
77997049Speter	static int dangling;
78097049Speter	char nbuf[MAXNBUF];
78197049Speter	char *p;
78297049Speter
78397049Speter	if (!msgbufmapped)
78497049Speter		return;
78597049Speter	if (c == '\0' || c == '\r')
78697049Speter		return;
78797049Speter	if (pri != -1 && pri != lastpri) {
78897049Speter		if (dangling) {
78997049Speter			msgbuf_addchar(msgbufp, '\n');
79097049Speter			dangling = 0;
79197049Speter		}
79297049Speter		msgbuf_addchar(msgbufp, '<');
79397049Speter		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
79497049Speter			msgbuf_addchar(msgbufp, *p--);
79597049Speter		msgbuf_addchar(msgbufp, '>');
79697049Speter		lastpri = pri;
79797049Speter	}
79897049Speter	msgbuf_addchar(msgbufp, c);
79997049Speter	if (c == '\n') {
80097049Speter		dangling = 0;
80197049Speter		lastpri = -1;
80297049Speter	} else {
80397049Speter		dangling = 1;
80497049Speter	}
80597049Speter}
80697049Speter
80797049Spetervoid
80897049Spetermsgbufinit(void *ptr, int size)
80997049Speter{
81097049Speter	char *cp;
81197049Speter	static struct msgbuf *oldp = NULL;
81297049Speter
81397049Speter	size -= sizeof(*msgbufp);
81497049Speter	cp = (char *)ptr;
81597049Speter	msgbufp = (struct msgbuf *)(cp + size);
81697049Speter	msgbuf_reinit(msgbufp, cp, size);
81797049Speter	if (msgbufmapped && oldp != msgbufp)
81897049Speter		msgbuf_copy(oldp, msgbufp);
81997049Speter	msgbufmapped = 1;
82097049Speter	oldp = msgbufp;
82197049Speter}
82297049Speter
82397049SpeterSYSCTL_DECL(_security_bsd);
82497049Speter
82597049Speterstatic int unprivileged_read_msgbuf = 1;
82697049SpeterSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
82797049Speter    CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
82897049Speter    "Unprivileged processes may read the kernel message buffer");
82997049Speter
83097049Speter/* Sysctls for accessing/clearing the msgbuf */
83197049Speterstatic int
83297049Spetersysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
83397049Speter{
83497049Speter	char buf[128];
83597049Speter	u_int seq;
83697049Speter	int error, len;
83797049Speter
83897049Speter	if (!unprivileged_read_msgbuf) {
83997049Speter		error = suser(req->td);
84097049Speter		if (error)
84197049Speter			return (error);
84297049Speter	}
84397049Speter
84497049Speter	/* Read the whole buffer, one chunk at a time. */
84597049Speter	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
84697049Speter	while ((len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq)) > 0) {
84797049Speter		error = sysctl_handle_opaque(oidp, buf, len, req);
84897049Speter		if (error)
84997049Speter			return (error);
85097049Speter	}
85197049Speter	return (0);
85297049Speter}
85397049Speter
85497049SpeterSYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
85597049Speter    0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
85697049Speter
85797049Speterstatic int msgbuf_clearflag;
85897049Speter
85997049Speterstatic int
86097049Spetersysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
86197049Speter{
86297049Speter	int error;
86397049Speter	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
86497049Speter	if (!error && req->newptr) {
86597049Speter		msgbuf_clear(msgbufp);
86697049Speter		msgbuf_clearflag = 0;
86797049Speter	}
86897049Speter	return (error);
86997049Speter}
87097049Speter
87197049SpeterSYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
87297049Speter    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clearflag, 0,
87397049Speter    sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
87497049Speter
87597049Speter#ifdef DDB
87697049Speter
87797049SpeterDB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
87897049Speter{
87997049Speter	int i, j;
88097049Speter
88197049Speter	if (!msgbufmapped) {
88297049Speter		db_printf("msgbuf not mapped yet\n");
88397049Speter		return;
88497049Speter	}
88597049Speter	db_printf("msgbufp = %p\n", msgbufp);
88697049Speter	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
88797049Speter	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
88897049Speter	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
88997049Speter	for (i = 0; i < msgbufp->msg_size; i++) {
89097049Speter		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
89197049Speter		db_printf("%c", msgbufp->msg_ptr[j]);
89297049Speter	}
89397049Speter	db_printf("\n");
89497049Speter}
89597049Speter
89697049Speter#endif /* DDB */
89797049Speter