hexdump.c revision 109623
138032Speter/*-
264562Sgshapiro * Copyright (c) 1986, 1988, 1991, 1993
338032Speter *	The Regents of the University of California.  All rights reserved.
490792Sgshapiro * (c) UNIX System Laboratories, Inc.
590792Sgshapiro * All or some portions of this file are derived from material licensed
690792Sgshapiro * to the University of California by American Telephone and Telegraph
790792Sgshapiro * Co. or Unix System Laboratories, Inc. and are reproduced herein with
838032Speter * the permission of UNIX System Laboratories, Inc.
990792Sgshapiro *
1090792Sgshapiro * Redistribution and use in source and binary forms, with or without
1190792Sgshapiro * modification, are permitted provided that the following conditions
1290792Sgshapiro * are met:
1338032Speter * 1. Redistributions of source code must retain the above copyright
1490792Sgshapiro *    notice, this list of conditions and the following disclaimer.
1538032Speter * 2. Redistributions in binary form must reproduce the above copyright
1690792Sgshapiro *    notice, this list of conditions and the following disclaimer in the
1790792Sgshapiro *    documentation and/or other materials provided with the distribution.
1890792Sgshapiro * 3. All advertising materials mentioning features or use of this software
1990792Sgshapiro *    must display the following acknowledgement:
2090792Sgshapiro *	This product includes software developed by the University of
2190792Sgshapiro *	California, Berkeley and its contributors.
2290792Sgshapiro * 4. Neither the name of the University nor the names of its contributors
2390792Sgshapiro *    may be used to endorse or promote products derived from this software
2490792Sgshapiro *    without specific prior written permission.
2590792Sgshapiro *
2690792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2790792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2890792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2990792Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3090792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31132943Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3290792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3390792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3490792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3590792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3690792Sgshapiro * SUCH DAMAGE.
3790792Sgshapiro *
3890792Sgshapiro *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
3990792Sgshapiro * $FreeBSD: head/sys/kern/subr_prf.c 109623 2003-01-21 08:56:16Z alfred $
4090792Sgshapiro */
4190792Sgshapiro
4290792Sgshapiro#include "opt_ddb.h"
4390792Sgshapiro
4490792Sgshapiro#include <sys/param.h>
4590792Sgshapiro#include <sys/systm.h>
4690792Sgshapiro#include <sys/lock.h>
4790792Sgshapiro#include <sys/mutex.h>
4890792Sgshapiro#include <sys/sx.h>
4938032Speter#include <sys/kernel.h>
5090792Sgshapiro#include <sys/msgbuf.h>
5138032Speter#include <sys/malloc.h>
5238032Speter#include <sys/proc.h>
5338032Speter#include <sys/stddef.h>
5438032Speter#include <sys/stdint.h>
5538032Speter#include <sys/sysctl.h>
5638032Speter#include <sys/tty.h>
5738032Speter#include <sys/syslog.h>
5838032Speter#include <sys/cons.h>
5938032Speter#include <sys/uio.h>
6038032Speter
6164562Sgshapiro#ifdef DDB
6264562Sgshapiro#include <ddb/ddb.h>
6364562Sgshapiro#endif
6464562Sgshapiro
6564562Sgshapiro/*
6638032Speter * Note that stdarg.h and the ANSI style va_start macro is used for both
6738032Speter * ANSI and traditional C compilers.
6838032Speter */
6938032Speter#include <machine/stdarg.h>
7038032Speter
7138032Speter#define TOCONS	0x01
7238032Speter#define TOTTY	0x02
7338032Speter#define TOLOG	0x04
7438032Speter
7538032Speter/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
7638032Speter#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
7738032Speter
7838032Speterstruct putchar_arg {
7938032Speter	int	flags;
80261194Sgshapiro	int	pri;
8164562Sgshapiro	struct	tty *tty;
8238032Speter};
8338032Speter
8438032Speterstruct snprintf_arg {
8538032Speter	char	*str;
8638032Speter	size_t	remain;
8738032Speter};
8838032Speter
8938032Speterextern	int log_open;
9038032Speter
9138032Speterstruct	tty *constty;			/* pointer to console "window" tty */
9238032Speter
9338032Speterstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
9438032Speterstatic void  msglogchar(int c, int pri);
9538032Speterstatic void  msgaddchar(int c, void *dummy);
9638032Speterstatic void  putchar(int ch, void *arg);
9738032Speterstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
9838032Speterstatic void  snprintf_func(int ch, void *arg);
9938032Speter
10038032Speterstatic int consintr = 1;		/* Ok to handle console interrupts? */
10138032Speterstatic int msgbufmapped;		/* Set when safe to use msgbuf */
10238032Speterint msgbuftrigger;
10338032Speter
10464562Sgshapirostatic int      log_console_output = 1;
10538032SpeterTUNABLE_INT("kern.log_console_output", &log_console_output);
10638032SpeterSYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW,
10738032Speter    &log_console_output, 0, "");
10838032Speter
10938032Speter/*
11064562Sgshapiro * Warn that a system table is full.
11138032Speter */
11238032Spetervoid
11338032Spetertablefull(const char *tab)
11464562Sgshapiro{
11538032Speter
11638032Speter	log(LOG_ERR, "%s: table is full\n", tab);
11738032Speter}
11838032Speter
11938032Speter/*
12038032Speter * Uprintf prints to the controlling terminal for the current process.
12138032Speter * It may block if the tty queue is overfull.  No message is printed if
12264562Sgshapiro * the queue does not clear in a reasonable time.
12338032Speter */
12438032Speterint
12564562Sgshapirouprintf(const char *fmt, ...)
12638032Speter{
12738032Speter	struct thread *td = curthread;
12838032Speter	struct proc *p = td->td_proc;
12964562Sgshapiro	va_list ap;
13064562Sgshapiro	struct putchar_arg pca;
13138032Speter	int retval;
13290792Sgshapiro
13390792Sgshapiro	if (td == NULL || td == PCPU_GET(idlethread))
134132943Sgshapiro		return (0);
135132943Sgshapiro
13638032Speter	p = td->td_proc;
13738032Speter	PROC_LOCK(p);
13838032Speter	if ((p->p_flag & P_CONTROLT) == 0) {
13938032Speter		PROC_UNLOCK(p);
14038032Speter		return (0);
14138032Speter	}
14238032Speter	SESS_LOCK(p->p_session);
14390792Sgshapiro	pca.tty = p->p_session->s_ttyp;
14464562Sgshapiro	SESS_UNLOCK(p->p_session);
14564562Sgshapiro	PROC_UNLOCK(p);
14638032Speter	if (pca.tty == NULL)
14764562Sgshapiro		return (0);
14864562Sgshapiro	pca.flags = TOTTY;
14964562Sgshapiro	va_start(ap, fmt);
15064562Sgshapiro	retval = kvprintf(fmt, putchar, &pca, 10, ap);
15138032Speter	va_end(ap);
15290792Sgshapiro
15390792Sgshapiro	return (retval);
15490792Sgshapiro}
15590792Sgshapiro
15690792Sgshapiro/*
15790792Sgshapiro * tprintf prints on the controlling terminal associated
15890792Sgshapiro * with the given session, possibly to the log as well.
15964562Sgshapiro */
16090792Sgshapirovoid
161285229Sgshapirotprintf(struct proc *p, int pri, const char *fmt, ...)
162285229Sgshapiro{
163285229Sgshapiro	struct tty *tp = NULL;
164285229Sgshapiro	int flags = 0, shld = 0;
165285229Sgshapiro	va_list ap;
166285229Sgshapiro	struct putchar_arg pca;
167285229Sgshapiro	int retval;
168285229Sgshapiro
169285229Sgshapiro	if (pri != -1)
170285229Sgshapiro		flags |= TOLOG;
171285229Sgshapiro	if (p != NULL) {
172285229Sgshapiro		PROC_LOCK(p);
173285229Sgshapiro		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
174285229Sgshapiro			SESS_LOCK(p->p_session);
175285229Sgshapiro			SESSHOLD(p->p_session);
176285229Sgshapiro			tp = p->p_session->s_ttyp;
177285229Sgshapiro			SESS_UNLOCK(p->p_session);
178285229Sgshapiro			PROC_UNLOCK(p);
179285229Sgshapiro			shld++;
180285229Sgshapiro			if (ttycheckoutq(tp, 0))
18138032Speter				flags |= TOTTY;
18238032Speter			else
18338032Speter				tp = NULL;
18438032Speter		} else
18538032Speter			PROC_UNLOCK(p);
18638032Speter	}
18738032Speter	pca.pri = pri;
18838032Speter	pca.tty = tp;
18938032Speter	pca.flags = flags;
19038032Speter	va_start(ap, fmt);
19138032Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
19238032Speter	va_end(ap);
19338032Speter	if (shld) {
19438032Speter		PROC_LOCK(p);
19538032Speter		SESS_LOCK(p->p_session);
19638032Speter		SESSRELE(p->p_session);
19738032Speter		SESS_UNLOCK(p->p_session);
19838032Speter		PROC_UNLOCK(p);
19938032Speter	}
20038032Speter	msgbuftrigger = 1;
20138032Speter}
20238032Speter
20364562Sgshapiro/*
20438032Speter * Ttyprintf displays a message on a tty; it should be used only by
20564562Sgshapiro * the tty driver, or anything that knows the underlying tty will not
20638032Speter * be revoke(2)'d away.  Other callers should use tprintf.
20738032Speter */
20838032Speterint
20938032Speterttyprintf(struct tty *tp, const char *fmt, ...)
21038032Speter{
21138032Speter	va_list ap;
21238032Speter	struct putchar_arg pca;
213110560Sgshapiro	int retval;
214110560Sgshapiro
215110560Sgshapiro	va_start(ap, fmt);
216110560Sgshapiro	pca.tty = tp;
217110560Sgshapiro	pca.flags = TOTTY;
218110560Sgshapiro	retval = kvprintf(fmt, putchar, &pca, 10, ap);
21990792Sgshapiro	va_end(ap);
220110560Sgshapiro	return (retval);
22190792Sgshapiro}
22290792Sgshapiro
22390792Sgshapiro/*
22490792Sgshapiro * Log writes to the log buffer, and guarantees not to sleep (so can be
22590792Sgshapiro * called by interrupt routines).  If there is no process reading the
22690792Sgshapiro * log yet, it writes to the console also.
22790792Sgshapiro */
22890792Sgshapirovoid
22990792Sgshapirolog(int level, const char *fmt, ...)
23090792Sgshapiro{
23190792Sgshapiro	va_list ap;
23290792Sgshapiro	int retval;
23390792Sgshapiro	struct putchar_arg pca;
23438032Speter
23538032Speter	pca.tty = NULL;
23638032Speter	pca.pri = level;
23738032Speter	pca.flags = log_open ? TOLOG : TOCONS;
23838032Speter
23938032Speter	va_start(ap, fmt);
24064562Sgshapiro	retval = kvprintf(fmt, putchar, &pca, 10, ap);
24164562Sgshapiro	va_end(ap);
24264562Sgshapiro
24364562Sgshapiro	msgbuftrigger = 1;
24464562Sgshapiro}
24538032Speter
24664562Sgshapiro#define CONSCHUNK 128
24764562Sgshapiro
24864562Sgshapirovoid
24964562Sgshapirolog_console(struct uio *uio)
25064562Sgshapiro{
25164562Sgshapiro	int c, i, error, iovlen, nl;
25264562Sgshapiro	struct uio muio;
25364562Sgshapiro	struct iovec *miov = NULL;
25464562Sgshapiro	char *consbuffer;
25564562Sgshapiro	int pri;
25664562Sgshapiro
25764562Sgshapiro	if (!log_console_output)
25864562Sgshapiro		return;
25964562Sgshapiro
26064562Sgshapiro	pri = LOG_INFO | LOG_CONSOLE;
26164562Sgshapiro	muio = *uio;
26264562Sgshapiro	iovlen = uio->uio_iovcnt * sizeof (struct iovec);
26364562Sgshapiro	MALLOC(miov, struct iovec *, iovlen, M_TEMP, 0);
26464562Sgshapiro	MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, 0);
26564562Sgshapiro	bcopy(muio.uio_iov, miov, iovlen);
26664562Sgshapiro	muio.uio_iov = miov;
26764562Sgshapiro	uio = &muio;
26864562Sgshapiro
26964562Sgshapiro	nl = 0;
27064562Sgshapiro	while (uio->uio_resid > 0) {
27164562Sgshapiro		c = imin(uio->uio_resid, CONSCHUNK);
27264562Sgshapiro		error = uiomove(consbuffer, c, uio);
27364562Sgshapiro		if (error != 0)
27464562Sgshapiro			break;
27564562Sgshapiro		for (i = 0; i < c; i++) {
27664562Sgshapiro			msglogchar(consbuffer[i], pri);
27764562Sgshapiro			if (consbuffer[i] == '\n')
27864562Sgshapiro				nl = 1;
27964562Sgshapiro			else
28064562Sgshapiro				nl = 0;
28164562Sgshapiro		}
28264562Sgshapiro	}
28364562Sgshapiro	if (!nl)
28464562Sgshapiro		msglogchar('\n', pri);
28564562Sgshapiro	msgbuftrigger = 1;
28664562Sgshapiro	FREE(miov, M_TEMP);
28764562Sgshapiro	FREE(consbuffer, M_TEMP);
28864562Sgshapiro	return;
28964562Sgshapiro}
29064562Sgshapiro
29164562Sgshapiroint
29264562Sgshapiroprintf(const char *fmt, ...)
29364562Sgshapiro{
29464562Sgshapiro	va_list ap;
29564562Sgshapiro	int savintr;
29680785Sgshapiro	struct putchar_arg pca;
29780785Sgshapiro	int retval;
29880785Sgshapiro
29980785Sgshapiro	savintr = consintr;		/* disable interrupts */
30080785Sgshapiro	consintr = 0;
30138032Speter	va_start(ap, fmt);
30238032Speter	pca.tty = NULL;
30338032Speter	pca.flags = TOCONS | TOLOG;
30438032Speter	pca.pri = -1;
30538032Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
30638032Speter	va_end(ap);
30738032Speter	if (!panicstr)
30838032Speter		msgbuftrigger = 1;
30938032Speter	consintr = savintr;		/* reenable interrupts */
31038032Speter	return (retval);
31138032Speter}
31238032Speter
31338032Speterint
31438032Spetervprintf(const char *fmt, va_list ap)
31538032Speter{
31638032Speter	int savintr;
31738032Speter	struct putchar_arg pca;
31838032Speter	int retval;
31938032Speter
32038032Speter	savintr = consintr;		/* disable interrupts */
32164562Sgshapiro	consintr = 0;
32238032Speter	pca.tty = NULL;
32338032Speter	pca.flags = TOCONS | TOLOG;
32438032Speter	pca.pri = -1;
32538032Speter	retval = kvprintf(fmt, putchar, &pca, 10, ap);
32638032Speter	if (!panicstr)
32738032Speter		msgbuftrigger = 1;
32864562Sgshapiro	consintr = savintr;		/* reenable interrupts */
32938032Speter	return (retval);
33038032Speter}
33138032Speter
33264562Sgshapiro/*
33364562Sgshapiro * Print a character on console or users terminal.  If destination is
33473188Sgshapiro * the console then the last bunch of characters are saved in msgbuf for
33564562Sgshapiro * inspection later.
33673188Sgshapiro */
33764562Sgshapirostatic void
33873188Sgshapiroputchar(int c, void *arg)
33973188Sgshapiro{
34090792Sgshapiro	struct putchar_arg *ap = (struct putchar_arg*) arg;
34190792Sgshapiro	int flags = ap->flags;
34290792Sgshapiro	struct tty *tp = ap->tty;
34390792Sgshapiro	if (panicstr)
34464562Sgshapiro		constty = NULL;
34538032Speter	if ((flags & TOCONS) && tp == NULL && constty) {
34638032Speter		tp = constty;
34764562Sgshapiro		flags |= TOTTY;
34864562Sgshapiro	}
34938032Speter	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
35038032Speter	    (flags & TOCONS) && tp == constty)
35138032Speter		constty = NULL;
35238032Speter	if ((flags & TOLOG))
35364562Sgshapiro		msglogchar(c, ap->pri);
35464562Sgshapiro	if ((flags & TOCONS) && constty == NULL && c != '\0')
35564562Sgshapiro		(*v_putc)(c);
35638032Speter}
35738032Speter
35838032Speter/*
35938032Speter * Scaled down version of sprintf(3).
36064562Sgshapiro */
36164562Sgshapiroint
36264562Sgshapirosprintf(char *buf, const char *cfmt, ...)
36364562Sgshapiro{
36464562Sgshapiro	int retval;
36538032Speter	va_list ap;
36638032Speter
36738032Speter	va_start(ap, cfmt);
36838032Speter	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
36938032Speter	buf[retval] = '\0';
37038032Speter	va_end(ap);
37138032Speter	return (retval);
37290792Sgshapiro}
37338032Speter
37438032Speter/*
37564562Sgshapiro * Scaled down version of vsprintf(3).
37638032Speter */
37790792Sgshapiroint
37890792Sgshapirovsprintf(char *buf, const char *cfmt, va_list ap)
37990792Sgshapiro{
38090792Sgshapiro	int retval;
381102528Sgshapiro
38238032Speter	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
38390792Sgshapiro	buf[retval] = '\0';
38438032Speter	return (retval);
38564562Sgshapiro}
38664562Sgshapiro
38764562Sgshapiro/*
38864562Sgshapiro * Scaled down version of snprintf(3).
38964562Sgshapiro */
39064562Sgshapiroint
39164562Sgshapirosnprintf(char *str, size_t size, const char *format, ...)
39238032Speter{
39364562Sgshapiro	int retval;
39438032Speter	va_list ap;
39564562Sgshapiro
39664562Sgshapiro	va_start(ap, format);
39764562Sgshapiro	retval = vsnprintf(str, size, format, ap);
39894334Sgshapiro	va_end(ap);
39994334Sgshapiro	return(retval);
40094334Sgshapiro}
40166494Sgshapiro
40238032Speter/*
40338032Speter * Scaled down version of vsnprintf(3).
40466494Sgshapiro */
40566494Sgshapiroint
40666494Sgshapirovsnprintf(char *str, size_t size, const char *format, va_list ap)
40766494Sgshapiro{
40890792Sgshapiro	struct snprintf_arg info;
40990792Sgshapiro	int retval;
41090792Sgshapiro
41190792Sgshapiro	info.str = str;
41290792Sgshapiro	info.remain = size;
41364562Sgshapiro	retval = kvprintf(format, snprintf_func, &info, 10, ap);
41464562Sgshapiro	if (info.remain >= 1)
41564562Sgshapiro		*info.str++ = '\0';
41638032Speter	return (retval);
41738032Speter}
41838032Speter
41938032Speterstatic void
420285229Sgshapirosnprintf_func(int ch, void *arg)
421285229Sgshapiro{
422285229Sgshapiro	struct snprintf_arg *const info = arg;
423285229Sgshapiro
424168515Sgshapiro	if (info->remain >= 2) {
425168515Sgshapiro		*info->str++ = ch;
426168515Sgshapiro		info->remain--;
42738032Speter	}
42838032Speter}
42938032Speter
43038032Speter/*
43138032Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
43238032Speter * order; return an optional length and a pointer to the last character
43338032Speter * written in the buffer (i.e., the first character of the string).
43438032Speter * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
43538032Speter */
43638032Speterstatic char *
43738032Speterksprintn(char *nbuf, uintmax_t num, int base, int *lenp)
43838032Speter{
43990792Sgshapiro	char *p;
44038032Speter
44138032Speter	p = nbuf;
44238032Speter	*p = '\0';
44338032Speter	do {
44438032Speter		*++p = hex2ascii(num % base);
44538032Speter	} while (num /= base);
44638032Speter	if (lenp)
44764562Sgshapiro		*lenp = p - nbuf;
44838032Speter	return (p);
44938032Speter}
45090792Sgshapiro
45138032Speter/*
45243730Speter * Scaled down version of printf(3).
45343730Speter *
45438032Speter * Two additional formats:
45564562Sgshapiro *
45643730Speter * The format %b is supported to decode error registers.
45738032Speter * Its usage is:
45838032Speter *
45938032Speter *	printf("reg=%b\n", regval, "<base><arg>*");
46043730Speter *
46138032Speter * where <base> is the output base expressed as a control character, e.g.
46238032Speter * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
46338032Speter * the first of which gives the bit number to be inspected (origin 1), and
46490792Sgshapiro * the next characters (up to a control character, i.e. a character <= 32),
46538032Speter * give the name of the register.  Thus:
46638032Speter *
46738032Speter *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
46838032Speter *
46990792Sgshapiro * would produce output:
47038032Speter *
47138032Speter *	reg=3<BITTWO,BITONE>
47264562Sgshapiro *
47364562Sgshapiro * XXX:  %D  -- Hexdump, takes pointer and separator string:
47438032Speter *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
47590792Sgshapiro *		("%*D", len, ptr, " " -> XX XX XX XX ...
47664562Sgshapiro */
47738032Speterint
47838032Speterkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
47938032Speter{
48038032Speter#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
48138032Speter	char nbuf[MAXNBUF];
48238032Speter	char *d;
48338032Speter	const char *p, *percent, *q;
48438032Speter	u_char *up;
48538032Speter	int ch, n;
48690792Sgshapiro	uintmax_t num;
48764562Sgshapiro	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
48864562Sgshapiro	int jflag, tflag, zflag;
48938032Speter	int dwidth;
49038032Speter	char padc;
49198121Sgshapiro	int retval = 0;
49298121Sgshapiro
49398121Sgshapiro	num = 0;
49498121Sgshapiro	if (!func)
49598121Sgshapiro		d = (char *) arg;
49698121Sgshapiro	else
49798121Sgshapiro		d = NULL;
49898121Sgshapiro
49998121Sgshapiro	if (fmt == NULL)
50098121Sgshapiro		fmt = "(fmt null)\n";
50198121Sgshapiro
50298121Sgshapiro	if (radix < 2 || radix > 36)
50398121Sgshapiro		radix = 10;
504110560Sgshapiro
505110560Sgshapiro	for (;;) {
506110560Sgshapiro		padc = ' ';
507110560Sgshapiro		width = 0;
50838032Speter		while ((ch = (u_char)*fmt++) != '%') {
50943730Speter			if (ch == '\0')
51043730Speter				return (retval);
51164562Sgshapiro			PCHAR(ch);
51264562Sgshapiro		}
51364562Sgshapiro		percent = fmt - 1;
51464562Sgshapiro		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
51564562Sgshapiro		sign = 0; dot = 0; dwidth = 0;
51664562Sgshapiro		jflag = 0; tflag = 0; zflag = 0;
51764562Sgshapiroreswitch:	switch (ch = (u_char)*fmt++) {
51890792Sgshapiro		case '.':
51990792Sgshapiro			dot = 1;
52038032Speter			goto reswitch;
52164562Sgshapiro		case '#':
522157001Sgshapiro			sharpflag = 1;
523157001Sgshapiro			goto reswitch;
524157001Sgshapiro		case '+':
525157001Sgshapiro			sign = 1;
526157001Sgshapiro			goto reswitch;
527157001Sgshapiro		case '-':
52838032Speter			ladjust = 1;
52964562Sgshapiro			goto reswitch;
53038032Speter		case '%':
53190792Sgshapiro			PCHAR(ch);
53290792Sgshapiro			break;
53390792Sgshapiro		case '*':
53464562Sgshapiro			if (!dot) {
53564562Sgshapiro				width = va_arg(ap, int);
53664562Sgshapiro				if (width < 0) {
53764562Sgshapiro					ladjust = !ladjust;
53864562Sgshapiro					width = -width;
53938032Speter				}
54038032Speter			} else {
54138032Speter				dwidth = va_arg(ap, int);
54238032Speter			}
54338032Speter			goto reswitch;
54464562Sgshapiro		case '0':
54538032Speter			if (!dot) {
54638032Speter				padc = '0';
54738032Speter				goto reswitch;
54838032Speter			}
54938032Speter		case '1': case '2': case '3': case '4':
55038032Speter		case '5': case '6': case '7': case '8': case '9':
55138032Speter				for (n = 0;; ++fmt) {
55238032Speter					n = n * 10 + ch - '0';
55338032Speter					ch = *fmt;
55438032Speter					if (ch < '0' || ch > '9')
55538032Speter						break;
55638032Speter				}
55738032Speter			if (dot)
55871345Sgshapiro				dwidth = n;
55982017Sgshapiro			else
56071345Sgshapiro				width = n;
56171345Sgshapiro			goto reswitch;
56290792Sgshapiro		case 'b':
56371345Sgshapiro			num = (u_int)va_arg(ap, int);
56471345Sgshapiro			p = va_arg(ap, char *);
56571345Sgshapiro			for (q = ksprintn(nbuf, num, *p++, NULL); *q;)
56671345Sgshapiro				PCHAR(*q--);
56771345Sgshapiro
56838032Speter			if (num == 0)
56964562Sgshapiro				break;
57064562Sgshapiro
57164562Sgshapiro			for (tmp = 0; *p;) {
57238032Speter				n = *p++;
57338032Speter				if (num & (1 << (n - 1))) {
57438032Speter					PCHAR(tmp ? ',' : '<');
57538032Speter					for (; (n = *p) > ' '; ++p)
57638032Speter						PCHAR(n);
57738032Speter					tmp = 1;
57838032Speter				} else
57938032Speter					for (; *p > ' '; ++p)
58038032Speter						continue;
58138032Speter			}
58238032Speter			if (tmp)
58338032Speter				PCHAR('>');
58438032Speter			break;
58538032Speter		case 'c':
58638032Speter			PCHAR(va_arg(ap, int));
58738032Speter			break;
58838032Speter		case 'D':
58938032Speter			up = va_arg(ap, u_char *);
59038032Speter			p = va_arg(ap, char *);
59138032Speter			if (!width)
59290792Sgshapiro				width = 16;
59338032Speter			while(width--) {
59438032Speter				PCHAR(hex2ascii(*up >> 4));
59538032Speter				PCHAR(hex2ascii(*up & 0x0f));
59638032Speter				up++;
59738032Speter				if (width)
59838032Speter					for (q=p;*q;q++)
59990792Sgshapiro						PCHAR(*q);
60038032Speter			}
60138032Speter			break;
60238032Speter		case 'd':
60338032Speter		case 'i':
60438032Speter			base = 10;
60538032Speter			sign = 1;
60638032Speter			goto handle_sign;
60738032Speter		case 'j':
60838032Speter			jflag = 1;
60938032Speter			goto reswitch;
61064562Sgshapiro		case 'l':
61138032Speter			if (lflag) {
61238032Speter				lflag = 0;
61338032Speter				qflag = 1;
61438032Speter			} else
61564562Sgshapiro				lflag = 1;
61664562Sgshapiro			goto reswitch;
61764562Sgshapiro		case 'n':
61838032Speter			if (jflag)
61966494Sgshapiro				*(va_arg(ap, intmax_t *)) = retval;
62038032Speter			else if (qflag)
62138032Speter				*(va_arg(ap, quad_t *)) = retval;
62238032Speter			else if (lflag)
62338032Speter				*(va_arg(ap, long *)) = retval;
62490792Sgshapiro			else if (zflag)
62590792Sgshapiro				*(va_arg(ap, size_t *)) = retval;
62690792Sgshapiro			else
62738032Speter				*(va_arg(ap, int *)) = retval;
62864562Sgshapiro			break;
62964562Sgshapiro		case 'o':
63064562Sgshapiro			base = 8;
63138032Speter			goto handle_nosign;
63238032Speter		case 'p':
63338032Speter			base = 16;
63438032Speter			sharpflag = (width == 0);
63538032Speter			sign = 0;
63638032Speter			num = (uintptr_t)va_arg(ap, void *);
63738032Speter			goto number;
63838032Speter		case 'q':
63938032Speter			qflag = 1;
64038032Speter			goto reswitch;
64138032Speter		case 'r':
64238032Speter			base = radix;
64338032Speter			if (sign)
64471345Sgshapiro				goto handle_sign;
64538032Speter			goto handle_nosign;
64638032Speter		case 's':
64738032Speter			p = va_arg(ap, char *);
64838032Speter			if (p == NULL)
64938032Speter				p = "(null)";
65038032Speter			if (!dot)
65138032Speter				n = strlen (p);
65238032Speter			else
65338032Speter				for (n = 0; n < dwidth && p[n]; n++)
65438032Speter					continue;
65538032Speter
65638032Speter			width -= n;
65738032Speter
65838032Speter			if (!ladjust && width > 0)
65938032Speter				while (width--)
66038032Speter					PCHAR(padc);
66138032Speter			while (n--)
662111823Sgshapiro				PCHAR(*p++);
663111823Sgshapiro			if (ladjust && width > 0)
66443730Speter				while (width--)
66538032Speter					PCHAR(padc);
66638032Speter			break;
66790792Sgshapiro		case 't':
66890792Sgshapiro			tflag = 1;
66990792Sgshapiro			goto reswitch;
67038032Speter			break;
67138032Speter		case 'u':
67238032Speter			base = 10;
67338032Speter			goto handle_nosign;
67438032Speter		case 'x':
67538032Speter		case 'X':
67638032Speter			base = 16;
67738032Speter			goto handle_nosign;
67838032Speter		case 'y':
67938032Speter			base = 16;
68038032Speter			sign = 1;
68138032Speter			goto handle_sign;
68238032Speter		case 'z':
68390792Sgshapiro			zflag = 1;
68490792Sgshapiro			goto reswitch;
68590792Sgshapirohandle_nosign:
68690792Sgshapiro			sign = 0;
68790792Sgshapiro			if (jflag)
68890792Sgshapiro				num = va_arg(ap, uintmax_t);
68938032Speter			else if (qflag)
69098121Sgshapiro				num = va_arg(ap, u_quad_t);
69198121Sgshapiro			else if (tflag)
69298121Sgshapiro				num = va_arg(ap, ptrdiff_t);
69398121Sgshapiro			else if (lflag)
69498121Sgshapiro				num = va_arg(ap, u_long);
69598121Sgshapiro			else if (zflag)
69698121Sgshapiro				num = va_arg(ap, size_t);
69798121Sgshapiro			else
69864562Sgshapiro				num = va_arg(ap, u_int);
69964562Sgshapiro			goto number;
70038032Speterhandle_sign:
70138032Speter			if (jflag)
70238032Speter				num = va_arg(ap, intmax_t);
70343730Speter			else if (qflag)
70443730Speter				num = va_arg(ap, quad_t);
70543730Speter			else if (tflag)
70643730Speter				num = va_arg(ap, ptrdiff_t);
70738032Speter			else if (lflag)
70838032Speter				num = va_arg(ap, long);
70938032Speter			else if (zflag)
71038032Speter				num = va_arg(ap, size_t);
71138032Speter			else
71238032Speter				num = va_arg(ap, int);
71338032Speternumber:
71438032Speter			if (sign && (intmax_t)num < 0) {
71538032Speter				neg = 1;
71643730Speter				num = -(intmax_t)num;
71738032Speter			}
71864562Sgshapiro			p = ksprintn(nbuf, num, base, &tmp);
71990792Sgshapiro			if (sharpflag && num != 0) {
72064562Sgshapiro				if (base == 8)
72138032Speter					tmp++;
72243730Speter				else if (base == 16)
72338032Speter					tmp += 2;
72438032Speter			}
72564562Sgshapiro			if (neg)
72638032Speter				tmp++;
72738032Speter
72838032Speter			if (!ladjust && width && (width -= tmp) > 0)
72938032Speter				while (width--)
73038032Speter					PCHAR(padc);
73164562Sgshapiro			if (neg)
73264562Sgshapiro				PCHAR('-');
73338032Speter			if (sharpflag && num != 0) {
73490792Sgshapiro				if (base == 8) {
73590792Sgshapiro					PCHAR('0');
73690792Sgshapiro				} else if (base == 16) {
73790792Sgshapiro					PCHAR('0');
73890792Sgshapiro					PCHAR('x');
73938032Speter				}
74038032Speter			}
74164562Sgshapiro
74264562Sgshapiro			while (*p)
74364562Sgshapiro				PCHAR(*p--);
74464562Sgshapiro
74564562Sgshapiro			if (ladjust && width && (width -= tmp) > 0)
74664562Sgshapiro				while (width--)
74764562Sgshapiro					PCHAR(padc);
74838032Speter
74964562Sgshapiro			break;
75064562Sgshapiro		default:
75164562Sgshapiro			while (percent < fmt)
75264562Sgshapiro				PCHAR(*percent++);
75364562Sgshapiro			break;
75438032Speter		}
75538032Speter	}
75664562Sgshapiro#undef PCHAR
75738032Speter}
75838032Speter
75938032Speter/*
76064562Sgshapiro * Put character in log buffer with a particular priority.
76164562Sgshapiro */
76264562Sgshapirostatic void
76364562Sgshapiromsglogchar(int c, int pri)
76464562Sgshapiro{
76564562Sgshapiro	static int lastpri = -1;
76690792Sgshapiro	static int dangling;
76764562Sgshapiro	char nbuf[MAXNBUF];
76864562Sgshapiro	char *p;
76938032Speter
770285229Sgshapiro	if (!msgbufmapped)
771285229Sgshapiro		return;
772285229Sgshapiro	if (c == '\0' || c == '\r')
773285229Sgshapiro		return;
774285229Sgshapiro	if (pri != -1 && pri != lastpri) {
775285229Sgshapiro		if (dangling) {
776285229Sgshapiro			msgaddchar('\n', NULL);
777285229Sgshapiro			dangling = 0;
778285229Sgshapiro		}
779285229Sgshapiro		msgaddchar('<', NULL);
78064562Sgshapiro		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
78171345Sgshapiro			msgaddchar(*p--, NULL);
78271345Sgshapiro		msgaddchar('>', NULL);
78371345Sgshapiro		lastpri = pri;
78471345Sgshapiro	}
78564562Sgshapiro	msgaddchar(c, NULL);
78664562Sgshapiro	if (c == '\n') {
78764562Sgshapiro		dangling = 0;
78864562Sgshapiro		lastpri = -1;
78964562Sgshapiro	} else {
79064562Sgshapiro		dangling = 1;
79164562Sgshapiro	}
79264562Sgshapiro}
79364562Sgshapiro
79438032Speter/*
79564562Sgshapiro * Put char in log buffer
79664562Sgshapiro */
79764562Sgshapirostatic void
79864562Sgshapiromsgaddchar(int c, void *dummy)
79964562Sgshapiro{
80064562Sgshapiro	struct msgbuf *mbp;
80164562Sgshapiro
80264562Sgshapiro	if (!msgbufmapped)
80364562Sgshapiro		return;
80464562Sgshapiro	mbp = msgbufp;
80564562Sgshapiro	mbp->msg_ptr[mbp->msg_bufx++] = c;
80664562Sgshapiro	if (mbp->msg_bufx >= mbp->msg_size)
80764562Sgshapiro		mbp->msg_bufx = 0;
80864562Sgshapiro	/* If the buffer is full, keep the most recent data. */
80964562Sgshapiro	if (mbp->msg_bufr == mbp->msg_bufx) {
81064562Sgshapiro		if (++mbp->msg_bufr >= mbp->msg_size)
81164562Sgshapiro			mbp->msg_bufr = 0;
81264562Sgshapiro	}
81364562Sgshapiro}
81464562Sgshapiro
81564562Sgshapirostatic void
81671345Sgshapiromsgbufcopy(struct msgbuf *oldp)
81771345Sgshapiro{
81871345Sgshapiro	int pos;
81938032Speter
82073188Sgshapiro	pos = oldp->msg_bufr;
82171345Sgshapiro	while (pos != oldp->msg_bufx) {
82271345Sgshapiro		msglogchar(oldp->msg_ptr[pos], -1);
82371345Sgshapiro		if (++pos >= oldp->msg_size)
82471345Sgshapiro			pos = 0;
82571345Sgshapiro	}
82671345Sgshapiro}
82771345Sgshapiro
82871345Sgshapirovoid
82971345Sgshapiromsgbufinit(void *ptr, int size)
83071345Sgshapiro{
83171345Sgshapiro	char *cp;
83271345Sgshapiro	static struct msgbuf *oldp = NULL;
83338032Speter
83464562Sgshapiro	size -= sizeof(*msgbufp);
83564562Sgshapiro	cp = (char *)ptr;
83664562Sgshapiro	msgbufp = (struct msgbuf *) (cp + size);
83764562Sgshapiro	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
83843730Speter	    msgbufp->msg_bufx >= size || msgbufp->msg_bufx < 0 ||
83964562Sgshapiro	    msgbufp->msg_bufr >= size || msgbufp->msg_bufr < 0) {
84043730Speter		bzero(cp, size);
84138032Speter		bzero(msgbufp, sizeof(*msgbufp));
84238032Speter		msgbufp->msg_magic = MSG_MAGIC;
84364562Sgshapiro		msgbufp->msg_size = (char *)msgbufp - cp;
84464562Sgshapiro	}
84564562Sgshapiro	msgbufp->msg_ptr = cp;
84638032Speter	if (msgbufmapped && oldp != msgbufp)
84738032Speter		msgbufcopy(oldp);
84838032Speter	msgbufmapped = 1;
84938032Speter	oldp = msgbufp;
85038032Speter}
85138032Speter
85238032SpeterSYSCTL_DECL(_security_bsd);
85338032Speter
85438032Speterstatic int unprivileged_read_msgbuf = 1;
85538032SpeterSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
85638032Speter    CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
85764562Sgshapiro    "Unprivileged processes may read the kernel message buffer");
85864562Sgshapiro
85964562Sgshapiro/* Sysctls for accessing/clearing the msgbuf */
86064562Sgshapirostatic int
86138032Spetersysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
86238032Speter{
86338032Speter	int error;
86438032Speter
86538032Speter	if (!unprivileged_read_msgbuf) {
86638032Speter		error = suser(req->td);
86738032Speter		if (error)
86838032Speter			return (error);
86943730Speter	}
87064562Sgshapiro
87143730Speter	/*
87238032Speter	 * Unwind the buffer, so that it's linear (possibly starting with
87338032Speter	 * some initial nulls).
87438032Speter	 */
87538032Speter	error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
87638032Speter	    msgbufp->msg_size - msgbufp->msg_bufx, req);
87738032Speter	if (error)
87838032Speter		return (error);
87938032Speter	if (msgbufp->msg_bufx > 0) {
88038032Speter		error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
88138032Speter		    msgbufp->msg_bufx, req);
88243730Speter	}
88364562Sgshapiro	return (error);
88443730Speter}
88538032Speter
88638032SpeterSYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
88738032Speter    0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
88838032Speter
88938032Speterstatic int msgbuf_clear;
89043730Speter
89164562Sgshapirostatic int
89243730Spetersysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
89338032Speter{
89438032Speter	int error;
89538032Speter	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
89638032Speter	if (!error && req->newptr) {
89738032Speter		/* Clear the buffer and reset write pointer */
89838032Speter		bzero(msgbufp->msg_ptr, msgbufp->msg_size);
89938032Speter		msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
90038032Speter		msgbuf_clear = 0;
90190792Sgshapiro	}
90290792Sgshapiro	return (error);
90338032Speter}
90438032Speter
90538032SpeterSYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
90638032Speter    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
90738032Speter    sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
90838032Speter
90938032Speter#ifdef DDB
91038032Speter
91138032SpeterDB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
91238032Speter{
91338032Speter	int i, j;
91438032Speter
91538032Speter	if (!msgbufmapped) {
91638032Speter		db_printf("msgbuf not mapped yet\n");
91738032Speter		return;
91864562Sgshapiro	}
91964562Sgshapiro	db_printf("msgbufp = %p\n", msgbufp);
92064562Sgshapiro	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
92164562Sgshapiro	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
92264562Sgshapiro	    msgbufp->msg_bufx, msgbufp->msg_ptr);
92338032Speter	for (i = 0; i < msgbufp->msg_size; i++) {
92438032Speter		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
92564562Sgshapiro		db_printf("%c", msgbufp->msg_ptr[j]);
92638032Speter	}
92738032Speter	db_printf("\n");
92838032Speter}
92938032Speter
93038032Speter#endif /* DDB */
93138032Speter