xref: /freebsd/sys/kern/subr_prf.c (revision 0a7139485ccb8192e7c7c6d93653da92bfcdc196)
1df8bae1dSRodney W. Grimes /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4df8bae1dSRodney W. Grimes  * Copyright (c) 1986, 1988, 1991, 1993
5df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
7df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
8df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
9df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
11df8bae1dSRodney W. Grimes  *
12df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
13df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
14df8bae1dSRodney W. Grimes  * are met:
15df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
17df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
18df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
19df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
2069a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
21df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22df8bae1dSRodney W. Grimes  *    without specific prior written permission.
23df8bae1dSRodney W. Grimes  *
24df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
35df8bae1dSRodney W. Grimes  *
36df8bae1dSRodney W. Grimes  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
37df8bae1dSRodney W. Grimes  */
38df8bae1dSRodney W. Grimes 
39677b542eSDavid E. O'Brien #include <sys/cdefs.h>
405672fac9SKenneth D. Merry #ifdef _KERNEL
413ae59505SPoul-Henning Kamp #include "opt_ddb.h"
42e0b65125SJohn Birrell #include "opt_printf.h"
435672fac9SKenneth D. Merry #endif  /* _KERNEL */
443ae59505SPoul-Henning Kamp 
45df8bae1dSRodney W. Grimes #include <sys/param.h>
465672fac9SKenneth D. Merry #ifdef _KERNEL
47df8bae1dSRodney W. Grimes #include <sys/systm.h>
48f591779bSSeigo Tanimura #include <sys/lock.h>
4982ebaee7SMarcel Moolenaar #include <sys/kdb.h>
50f591779bSSeigo Tanimura #include <sys/mutex.h>
51f591779bSSeigo Tanimura #include <sys/sx.h>
52e796e00dSPoul-Henning Kamp #include <sys/kernel.h>
53df8bae1dSRodney W. Grimes #include <sys/msgbuf.h>
54a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
55acd3428bSRobert Watson #include <sys/priv.h>
56df8bae1dSRodney W. Grimes #include <sys/proc.h>
572bb95458SMaxime Henrion #include <sys/stddef.h>
5858a24f79SPoul-Henning Kamp #include <sys/sysctl.h>
599d6ae1e3SColin Percival #include <sys/tslog.h>
60df8bae1dSRodney W. Grimes #include <sys/tty.h>
61df8bae1dSRodney W. Grimes #include <sys/syslog.h>
62ce9edcf5SPoul-Henning Kamp #include <sys/cons.h>
63e2a09b26SPoul-Henning Kamp #include <sys/uio.h>
647d7db529SConrad Meyer #else /* !_KERNEL */
657d7db529SConrad Meyer #include <errno.h>
665672fac9SKenneth D. Merry #endif
670d84d9ebSJung-uk Kim #include <sys/ctype.h>
685672fac9SKenneth D. Merry #include <sys/sbuf.h>
69df8bae1dSRodney W. Grimes 
703ae59505SPoul-Henning Kamp #ifdef DDB
713ae59505SPoul-Henning Kamp #include <ddb/ddb.h>
723ae59505SPoul-Henning Kamp #endif
733ae59505SPoul-Henning Kamp 
74df8bae1dSRodney W. Grimes /*
75df8bae1dSRodney W. Grimes  * Note that stdarg.h and the ANSI style va_start macro is used for both
76df8bae1dSRodney W. Grimes  * ANSI and traditional C compilers.
77df8bae1dSRodney W. Grimes  */
7807f862a7SMarcel Moolenaar #ifdef _KERNEL
79df8bae1dSRodney W. Grimes #include <machine/stdarg.h>
8007f862a7SMarcel Moolenaar #else
8107f862a7SMarcel Moolenaar #include <stdarg.h>
8238e41e66SScott Long #endif
8338e41e66SScott Long 
8438e41e66SScott Long /*
8538e41e66SScott Long  * This is needed for sbuf_putbuf() when compiled into userland.  Due to the
8638e41e66SScott Long  * shared nature of this file, it's the only place to put it.
8738e41e66SScott Long  */
8838e41e66SScott Long #ifndef _KERNEL
89c4e92994SJung-uk Kim #include <stdio.h>
9007f862a7SMarcel Moolenaar #endif
91df8bae1dSRodney W. Grimes 
925672fac9SKenneth D. Merry #ifdef _KERNEL
935672fac9SKenneth D. Merry 
94df8bae1dSRodney W. Grimes #define TOCONS	0x01
95df8bae1dSRodney W. Grimes #define TOTTY	0x02
96df8bae1dSRodney W. Grimes #define TOLOG	0x04
97df8bae1dSRodney W. Grimes 
9882941964SPeter Wemm /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
993b1f7e7dSDag-Erling Smørgrav #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
100df8bae1dSRodney W. Grimes 
1018245f3f5SArchie Cobbs struct putchar_arg {
1028245f3f5SArchie Cobbs 	int	flags;
103e2a09b26SPoul-Henning Kamp 	int	pri;
1048245f3f5SArchie Cobbs 	struct	tty *tty;
1053d068827SJohn Birrell 	char	*p_bufr;
1063d068827SJohn Birrell 	size_t	n_bufr;
1073d068827SJohn Birrell 	char	*p_next;
1083d068827SJohn Birrell 	size_t	remain;
1098245f3f5SArchie Cobbs };
1108245f3f5SArchie Cobbs 
1118245f3f5SArchie Cobbs struct snprintf_arg {
1128245f3f5SArchie Cobbs 	char	*str;
1138245f3f5SArchie Cobbs 	size_t	remain;
1148245f3f5SArchie Cobbs };
1158245f3f5SArchie Cobbs 
116e2a09b26SPoul-Henning Kamp extern	int log_open;
117e2a09b26SPoul-Henning Kamp 
118e2a09b26SPoul-Henning Kamp static void  msglogchar(int c, int pri);
119d42a4eb5SKenneth D. Merry static void  msglogstr(char *str, int pri, int filter_cr);
120a264594dSAlexander Motin static void  prf_putbuf(char *bufr, int flags, int pri);
1214d77a549SAlfred Perlstein static void  putchar(int ch, void *arg);
1220d84d9ebSJung-uk Kim static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
1234d77a549SAlfred Perlstein static void  snprintf_func(int ch, void *arg);
124df8bae1dSRodney W. Grimes 
12521aa6e83SKyle Evans static bool msgbufmapped;		/* Set when safe to use msgbuf */
126e2a09b26SPoul-Henning Kamp int msgbuftrigger;
127fb3cc1c3SBruce Evans struct msgbuf *msgbufp;
128df8bae1dSRodney W. Grimes 
1292a4650ccSKyle Evans #ifndef BOOT_TAG_SZ
1302a4650ccSKyle Evans #define	BOOT_TAG_SZ	32
1312a4650ccSKyle Evans #endif
1322a4650ccSKyle Evans #ifndef BOOT_TAG
1332a4650ccSKyle Evans /* Tag used to mark the start of a boot in dmesg */
1342a4650ccSKyle Evans #define	BOOT_TAG	"---<<BOOT>>---"
1352a4650ccSKyle Evans #endif
1362a4650ccSKyle Evans 
1372a4650ccSKyle Evans static char current_boot_tag[BOOT_TAG_SZ + 1] = BOOT_TAG;
1382a4650ccSKyle Evans SYSCTL_STRING(_kern, OID_AUTO, boot_tag, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
1392a4650ccSKyle Evans     current_boot_tag, 0, "Tag added to dmesg at start of boot");
1402a4650ccSKyle Evans 
141dbe620d3SDavid Malone static int log_console_output = 1;
142af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
143af3b2549SHans Petter Selasky     &log_console_output, 0, "Duplicate console output to the syslog");
1448e1b7974SBrian Feldman 
145d42a4eb5SKenneth D. Merry /*
146d42a4eb5SKenneth D. Merry  * See the comment in log_console() below for more explanation of this.
147d42a4eb5SKenneth D. Merry  */
148af3b2549SHans Petter Selasky static int log_console_add_linefeed;
149af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
150af3b2549SHans Petter Selasky     &log_console_add_linefeed, 0, "log_console() adds extra newlines");
151d42a4eb5SKenneth D. Merry 
152af3b2549SHans Petter Selasky static int always_console_output;
153af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
154af3b2549SHans Petter Selasky     &always_console_output, 0, "Always output to console despite TIOCCONS");
155dbe620d3SDavid Malone 
156df8bae1dSRodney W. Grimes /*
157df8bae1dSRodney W. Grimes  * Warn that a system table is full.
158df8bae1dSRodney W. Grimes  */
159df8bae1dSRodney W. Grimes void
160e2a09b26SPoul-Henning Kamp tablefull(const char *tab)
161df8bae1dSRodney W. Grimes {
162df8bae1dSRodney W. Grimes 
163df8bae1dSRodney W. Grimes 	log(LOG_ERR, "%s: table is full\n", tab);
164df8bae1dSRodney W. Grimes }
165df8bae1dSRodney W. Grimes 
166df8bae1dSRodney W. Grimes /*
167df8bae1dSRodney W. Grimes  * Uprintf prints to the controlling terminal for the current process.
168df8bae1dSRodney W. Grimes  */
169f1550d9dSDoug Rabson int
170df8bae1dSRodney W. Grimes uprintf(const char *fmt, ...)
171df8bae1dSRodney W. Grimes {
172df8bae1dSRodney W. Grimes 	va_list ap;
173791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
174ff7b7d90SEd Schouten 	struct proc *p;
175ff7b7d90SEd Schouten 	struct thread *td;
176f591779bSSeigo Tanimura 	int retval;
177df8bae1dSRodney W. Grimes 
178ff7b7d90SEd Schouten 	td = curthread;
179ff7b7d90SEd Schouten 	if (TD_IS_IDLETHREAD(td))
180f591779bSSeigo Tanimura 		return (0);
181f591779bSSeigo Tanimura 
1827e99c034SAlex Richardson 	if (td->td_proc == initproc) {
1837e99c034SAlex Richardson 		/* Produce output when we fail to load /sbin/init: */
1847e99c034SAlex Richardson 		va_start(ap, fmt);
1857e99c034SAlex Richardson 		retval = vprintf(fmt, ap);
1867e99c034SAlex Richardson 		va_end(ap);
1877e99c034SAlex Richardson 		return (retval);
1887e99c034SAlex Richardson 	}
1897e99c034SAlex Richardson 
190bc093719SEd Schouten 	sx_slock(&proctree_lock);
191ff7b7d90SEd Schouten 	p = td->td_proc;
192f591779bSSeigo Tanimura 	PROC_LOCK(p);
193f591779bSSeigo Tanimura 	if ((p->p_flag & P_CONTROLT) == 0) {
194f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
1958740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
1968740a711SKonstantin Belousov 		return (0);
197f591779bSSeigo Tanimura 	}
198f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
199791d77e0SPoul-Henning Kamp 	pca.tty = p->p_session->s_ttyp;
200f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
201f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
202329c75a7SRobert Watson 	if (pca.tty == NULL) {
2038740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
2048740a711SKonstantin Belousov 		return (0);
205329c75a7SRobert Watson 	}
206791d77e0SPoul-Henning Kamp 	pca.flags = TOTTY;
2075e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
208f591779bSSeigo Tanimura 	va_start(ap, fmt);
209bc093719SEd Schouten 	tty_lock(pca.tty);
2108740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
211f1550d9dSDoug Rabson 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
212bc093719SEd Schouten 	tty_unlock(pca.tty);
213df8bae1dSRodney W. Grimes 	va_end(ap);
21458a24f79SPoul-Henning Kamp 	return (retval);
215df8bae1dSRodney W. Grimes }
216df8bae1dSRodney W. Grimes 
217df8bae1dSRodney W. Grimes /*
21834c916c6SNavdeep Parhar  * tprintf and vtprintf print on the controlling terminal associated with the
21934c916c6SNavdeep Parhar  * given session, possibly to the log as well.
220df8bae1dSRodney W. Grimes  */
221a52585d7SPoul-Henning Kamp void
222a52585d7SPoul-Henning Kamp tprintf(struct proc *p, int pri, const char *fmt, ...)
223df8bae1dSRodney W. Grimes {
22434c916c6SNavdeep Parhar 	va_list ap;
22534c916c6SNavdeep Parhar 
22634c916c6SNavdeep Parhar 	va_start(ap, fmt);
22734c916c6SNavdeep Parhar 	vtprintf(p, pri, fmt, ap);
22834c916c6SNavdeep Parhar 	va_end(ap);
22934c916c6SNavdeep Parhar }
23034c916c6SNavdeep Parhar 
23134c916c6SNavdeep Parhar void
23234c916c6SNavdeep Parhar vtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
23334c916c6SNavdeep Parhar {
234df8bae1dSRodney W. Grimes 	struct tty *tp = NULL;
235b5a2bad1SJohn Baldwin 	int flags = 0;
236791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
237b5a2bad1SJohn Baldwin 	struct session *sess = NULL;
238df8bae1dSRodney W. Grimes 
239bc093719SEd Schouten 	sx_slock(&proctree_lock);
240e2a09b26SPoul-Henning Kamp 	if (pri != -1)
241a52585d7SPoul-Henning Kamp 		flags |= TOLOG;
242f591779bSSeigo Tanimura 	if (p != NULL) {
243f591779bSSeigo Tanimura 		PROC_LOCK(p);
244f591779bSSeigo Tanimura 		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
245b5a2bad1SJohn Baldwin 			sess = p->p_session;
246bc093719SEd Schouten 			sess_hold(sess);
247f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
248b5a2bad1SJohn Baldwin 			tp = sess->s_ttyp;
249bc093719SEd Schouten 			if (tp != NULL && tty_checkoutq(tp))
250f591779bSSeigo Tanimura 				flags |= TOTTY;
251f591779bSSeigo Tanimura 			else
252f591779bSSeigo Tanimura 				tp = NULL;
253f591779bSSeigo Tanimura 		} else
254f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
255a52585d7SPoul-Henning Kamp 	}
256e2a09b26SPoul-Henning Kamp 	pca.pri = pri;
257791d77e0SPoul-Henning Kamp 	pca.tty = tp;
258791d77e0SPoul-Henning Kamp 	pca.flags = flags;
2595e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
260bc093719SEd Schouten 	if (pca.tty != NULL)
261bc093719SEd Schouten 		tty_lock(pca.tty);
2628740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
26374f1af01SPoul-Henning Kamp 	kvprintf(fmt, putchar, &pca, 10, ap);
264bc093719SEd Schouten 	if (pca.tty != NULL)
265bc093719SEd Schouten 		tty_unlock(pca.tty);
266572b4402SPoul-Henning Kamp 	if (sess != NULL)
267bc093719SEd Schouten 		sess_release(sess);
268e2a09b26SPoul-Henning Kamp 	msgbuftrigger = 1;
269df8bae1dSRodney W. Grimes }
270df8bae1dSRodney W. Grimes 
271ae8959ddSBryan Drewery static int
272ae8959ddSBryan Drewery _vprintf(int level, int flags, const char *fmt, va_list ap)
273df8bae1dSRodney W. Grimes {
274791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
275ae8959ddSBryan Drewery 	int retval;
276d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
277d42a4eb5SKenneth D. Merry 	char bufr[PRINTF_BUFR_SIZE];
278d42a4eb5SKenneth D. Merry #endif
279e2a09b26SPoul-Henning Kamp 
280d5d7606cSColin Percival 	TSENTER();
281791d77e0SPoul-Henning Kamp 	pca.tty = NULL;
282e2a09b26SPoul-Henning Kamp 	pca.pri = level;
283ae8959ddSBryan Drewery 	pca.flags = flags;
284d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
285d42a4eb5SKenneth D. Merry 	pca.p_bufr = bufr;
286d42a4eb5SKenneth D. Merry 	pca.p_next = pca.p_bufr;
287d42a4eb5SKenneth D. Merry 	pca.n_bufr = sizeof(bufr);
288d42a4eb5SKenneth D. Merry 	pca.remain = sizeof(bufr);
289d42a4eb5SKenneth D. Merry 	*pca.p_next = '\0';
290d42a4eb5SKenneth D. Merry #else
291ae8959ddSBryan Drewery 	/* Don't buffer console output. */
2923d068827SJohn Birrell 	pca.p_bufr = NULL;
293d42a4eb5SKenneth D. Merry #endif
294e2a09b26SPoul-Henning Kamp 
295ae8959ddSBryan Drewery 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
296e2a09b26SPoul-Henning Kamp 
297d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
298d42a4eb5SKenneth D. Merry 	/* Write any buffered console/log output: */
299a264594dSAlexander Motin 	if (*pca.p_bufr != '\0')
300a264594dSAlexander Motin 		prf_putbuf(pca.p_bufr, flags, level);
301d42a4eb5SKenneth D. Merry #endif
302ae8959ddSBryan Drewery 
303d5d7606cSColin Percival 	TSEXIT();
304ae8959ddSBryan Drewery 	return (retval);
305ae8959ddSBryan Drewery }
306ae8959ddSBryan Drewery 
307ae8959ddSBryan Drewery /*
308ae8959ddSBryan Drewery  * Log writes to the log buffer, and guarantees not to sleep (so can be
309ae8959ddSBryan Drewery  * called by interrupt routines).  If there is no process reading the
310ae8959ddSBryan Drewery  * log yet, it writes to the console also.
311ae8959ddSBryan Drewery  */
312ae8959ddSBryan Drewery void
313ae8959ddSBryan Drewery log(int level, const char *fmt, ...)
314ae8959ddSBryan Drewery {
315ae8959ddSBryan Drewery 	va_list ap;
316ae8959ddSBryan Drewery 
317ae8959ddSBryan Drewery 	va_start(ap, fmt);
31807713ddeSMark Johnston 	vlog(level, fmt, ap);
319ae8959ddSBryan Drewery 	va_end(ap);
32007713ddeSMark Johnston }
321ae8959ddSBryan Drewery 
32207713ddeSMark Johnston void
32307713ddeSMark Johnston vlog(int level, const char *fmt, va_list ap)
32407713ddeSMark Johnston {
32507713ddeSMark Johnston 
32607713ddeSMark Johnston 	(void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
327b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
328df8bae1dSRodney W. Grimes }
329df8bae1dSRodney W. Grimes 
330e2a09b26SPoul-Henning Kamp #define CONSCHUNK 128
331e2a09b26SPoul-Henning Kamp 
332e2a09b26SPoul-Henning Kamp void
333e2a09b26SPoul-Henning Kamp log_console(struct uio *uio)
334df8bae1dSRodney W. Grimes {
335d42a4eb5SKenneth D. Merry 	int c, error, nl;
336e2a09b26SPoul-Henning Kamp 	char *consbuffer;
337e2a09b26SPoul-Henning Kamp 	int pri;
338df8bae1dSRodney W. Grimes 
339dbe620d3SDavid Malone 	if (!log_console_output)
340dbe620d3SDavid Malone 		return;
341dbe620d3SDavid Malone 
342e2a09b26SPoul-Henning Kamp 	pri = LOG_INFO | LOG_CONSOLE;
343552afd9cSPoul-Henning Kamp 	uio = cloneuio(uio);
344552afd9cSPoul-Henning Kamp 	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
345e2a09b26SPoul-Henning Kamp 
3463a4d0c86SEd Schouten 	nl = 0;
347e2a09b26SPoul-Henning Kamp 	while (uio->uio_resid > 0) {
348d42a4eb5SKenneth D. Merry 		c = imin(uio->uio_resid, CONSCHUNK - 1);
349e2a09b26SPoul-Henning Kamp 		error = uiomove(consbuffer, c, uio);
350e2a09b26SPoul-Henning Kamp 		if (error != 0)
3512f9752e9SPoul-Henning Kamp 			break;
352d42a4eb5SKenneth D. Merry 		/* Make sure we're NUL-terminated */
353d42a4eb5SKenneth D. Merry 		consbuffer[c] = '\0';
354d42a4eb5SKenneth D. Merry 		if (consbuffer[c - 1] == '\n')
3553a4d0c86SEd Schouten 			nl = 1;
3563a4d0c86SEd Schouten 		else
3573a4d0c86SEd Schouten 			nl = 0;
358d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
359e2a09b26SPoul-Henning Kamp 	}
360d42a4eb5SKenneth D. Merry 	/*
361d42a4eb5SKenneth D. Merry 	 * The previous behavior in log_console() is preserved when
362d42a4eb5SKenneth D. Merry 	 * log_console_add_linefeed is non-zero.  For that behavior, if an
363d42a4eb5SKenneth D. Merry 	 * individual console write came in that was not terminated with a
364d42a4eb5SKenneth D. Merry 	 * line feed, it would add a line feed.
365d42a4eb5SKenneth D. Merry 	 *
366d42a4eb5SKenneth D. Merry 	 * This results in different data in the message buffer than
367d42a4eb5SKenneth D. Merry 	 * appears on the system console (which doesn't add extra line feed
368d42a4eb5SKenneth D. Merry 	 * characters).
369d42a4eb5SKenneth D. Merry 	 *
370d42a4eb5SKenneth D. Merry 	 * A number of programs and rc scripts write a line feed, or a period
371d42a4eb5SKenneth D. Merry 	 * and a line feed when they have completed their operation.  On
372d42a4eb5SKenneth D. Merry 	 * the console, this looks seamless, but when displayed with
373d42a4eb5SKenneth D. Merry 	 * 'dmesg -a', you wind up with output that looks like this:
374d42a4eb5SKenneth D. Merry 	 *
375d42a4eb5SKenneth D. Merry 	 * Updating motd:
376d42a4eb5SKenneth D. Merry 	 * .
377d42a4eb5SKenneth D. Merry 	 *
378d42a4eb5SKenneth D. Merry 	 * On the console, it looks like this:
379d42a4eb5SKenneth D. Merry 	 * Updating motd:.
380d42a4eb5SKenneth D. Merry 	 *
381d42a4eb5SKenneth D. Merry 	 * We could add logic to detect that situation, or just not insert
382d42a4eb5SKenneth D. Merry 	 * the extra newlines.  Set the kern.log_console_add_linefeed
383d42a4eb5SKenneth D. Merry 	 * sysctl/tunable variable to get the old behavior.
384d42a4eb5SKenneth D. Merry 	 */
385d42a4eb5SKenneth D. Merry 	if (!nl && log_console_add_linefeed) {
386d42a4eb5SKenneth D. Merry 		consbuffer[0] = '\n';
387d42a4eb5SKenneth D. Merry 		consbuffer[1] = '\0';
388d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
3893a4d0c86SEd Schouten 	}
390b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
391552afd9cSPoul-Henning Kamp 	free(uio, M_IOV);
392552afd9cSPoul-Henning Kamp 	free(consbuffer, M_TEMP);
393df8bae1dSRodney W. Grimes }
394df8bae1dSRodney W. Grimes 
3956ddbf1e2SGary Palmer int
396df8bae1dSRodney W. Grimes printf(const char *fmt, ...)
397df8bae1dSRodney W. Grimes {
398df8bae1dSRodney W. Grimes 	va_list ap;
39965ed8cbdSJustin T. Gibbs 	int retval;
4003d068827SJohn Birrell 
401df8bae1dSRodney W. Grimes 	va_start(ap, fmt);
40291c3cbfeSEd Schouten 	retval = vprintf(fmt, ap);
403df8bae1dSRodney W. Grimes 	va_end(ap);
4043d068827SJohn Birrell 
40558a24f79SPoul-Henning Kamp 	return (retval);
406df8bae1dSRodney W. Grimes }
407df8bae1dSRodney W. Grimes 
408f1550d9dSDoug Rabson int
409791d77e0SPoul-Henning Kamp vprintf(const char *fmt, va_list ap)
410791d77e0SPoul-Henning Kamp {
411f1550d9dSDoug Rabson 	int retval;
4123d068827SJohn Birrell 
413ae8959ddSBryan Drewery 	retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
4143d068827SJohn Birrell 
415879e0604SMateusz Guzik 	if (!KERNEL_PANICKED())
416b80e3b41SPoul-Henning Kamp 		msgbuftrigger = 1;
4173d068827SJohn Birrell 
41858a24f79SPoul-Henning Kamp 	return (retval);
419791d77e0SPoul-Henning Kamp }
420791d77e0SPoul-Henning Kamp 
4213d068827SJohn Birrell static void
422a264594dSAlexander Motin prf_putchar(int c, int flags, int pri)
423a264594dSAlexander Motin {
424a264594dSAlexander Motin 
425c545a7b2SChuck Silvers 	if (flags & TOLOG) {
426a264594dSAlexander Motin 		msglogchar(c, pri);
427c545a7b2SChuck Silvers 		msgbuftrigger = 1;
428c545a7b2SChuck Silvers 	}
429a264594dSAlexander Motin 
430a264594dSAlexander Motin 	if (flags & TOCONS) {
431a264594dSAlexander Motin 		if ((!KERNEL_PANICKED()) && (constty != NULL))
432a264594dSAlexander Motin 			msgbuf_addchar(&consmsgbuf, c);
433a264594dSAlexander Motin 
434a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
435a264594dSAlexander Motin 			cnputc(c);
436a264594dSAlexander Motin 	}
437a264594dSAlexander Motin }
438a264594dSAlexander Motin 
439a264594dSAlexander Motin static void
440388f3ce6SScott Long prf_putbuf(char *bufr, int flags, int pri)
441388f3ce6SScott Long {
442388f3ce6SScott Long 
443c545a7b2SChuck Silvers 	if (flags & TOLOG) {
444388f3ce6SScott Long 		msglogstr(bufr, pri, /*filter_cr*/1);
445c545a7b2SChuck Silvers 		msgbuftrigger = 1;
446c545a7b2SChuck Silvers 	}
447388f3ce6SScott Long 
448388f3ce6SScott Long 	if (flags & TOCONS) {
449879e0604SMateusz Guzik 		if ((!KERNEL_PANICKED()) && (constty != NULL))
450388f3ce6SScott Long 			msgbuf_addstr(&consmsgbuf, -1,
451388f3ce6SScott Long 			    bufr, /*filter_cr*/ 0);
452388f3ce6SScott Long 
453a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
454388f3ce6SScott Long 			cnputs(bufr);
455388f3ce6SScott Long 	}
456388f3ce6SScott Long }
457388f3ce6SScott Long 
458388f3ce6SScott Long static void
459d42a4eb5SKenneth D. Merry putbuf(int c, struct putchar_arg *ap)
4603d068827SJohn Birrell {
4613d068827SJohn Birrell 	/* Check if no console output buffer was provided. */
462d42a4eb5SKenneth D. Merry 	if (ap->p_bufr == NULL) {
463a264594dSAlexander Motin 		prf_putchar(c, ap->flags, ap->pri);
464d42a4eb5SKenneth D. Merry 	} else {
4653d068827SJohn Birrell 		/* Buffer the character: */
4663d068827SJohn Birrell 		*ap->p_next++ = c;
4673d068827SJohn Birrell 		ap->remain--;
4683d068827SJohn Birrell 
4693d068827SJohn Birrell 		/* Always leave the buffer zero terminated. */
4703d068827SJohn Birrell 		*ap->p_next = '\0';
4713d068827SJohn Birrell 
4723d068827SJohn Birrell 		/* Check if the buffer needs to be flushed. */
473d42a4eb5SKenneth D. Merry 		if (ap->remain == 2 || c == '\n') {
474388f3ce6SScott Long 			prf_putbuf(ap->p_bufr, ap->flags, ap->pri);
475d42a4eb5SKenneth D. Merry 
4763d068827SJohn Birrell 			ap->p_next = ap->p_bufr;
4773d068827SJohn Birrell 			ap->remain = ap->n_bufr;
4783d068827SJohn Birrell 			*ap->p_next = '\0';
4793d068827SJohn Birrell 		}
480d42a4eb5SKenneth D. Merry 
481d42a4eb5SKenneth D. Merry 		/*
482d42a4eb5SKenneth D. Merry 		 * Since we fill the buffer up one character at a time,
483d42a4eb5SKenneth D. Merry 		 * this should not happen.  We should always catch it when
484d42a4eb5SKenneth D. Merry 		 * ap->remain == 2 (if not sooner due to a newline), flush
485d42a4eb5SKenneth D. Merry 		 * the buffer and move on.  One way this could happen is
486d42a4eb5SKenneth D. Merry 		 * if someone sets PRINTF_BUFR_SIZE to 1 or something
487d42a4eb5SKenneth D. Merry 		 * similarly silly.
488d42a4eb5SKenneth D. Merry 		 */
489d42a4eb5SKenneth D. Merry 		KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
490d42a4eb5SKenneth D. Merry 		    ap->remain));
4913d068827SJohn Birrell 	}
4923d068827SJohn Birrell }
4933d068827SJohn Birrell 
494791d77e0SPoul-Henning Kamp /*
495791d77e0SPoul-Henning Kamp  * Print a character on console or users terminal.  If destination is
496e796e00dSPoul-Henning Kamp  * the console then the last bunch of characters are saved in msgbuf for
497791d77e0SPoul-Henning Kamp  * inspection later.
498791d77e0SPoul-Henning Kamp  */
499791d77e0SPoul-Henning Kamp static void
500791d77e0SPoul-Henning Kamp putchar(int c, void *arg)
501791d77e0SPoul-Henning Kamp {
502791d77e0SPoul-Henning Kamp 	struct putchar_arg *ap = (struct putchar_arg*) arg;
503791d77e0SPoul-Henning Kamp 	struct tty *tp = ap->tty;
5043d068827SJohn Birrell 	int flags = ap->flags;
505d29bf12fSIan Dowse 
506adef9265SIan Dowse 	/* Don't use the tty code after a panic or while in ddb. */
5073d068827SJohn Birrell 	if (kdb_active) {
508d29bf12fSIan Dowse 		if (c != '\0')
509d29bf12fSIan Dowse 			cnputc(c);
51080f1c58bSMarcel Moolenaar 		return;
51180f1c58bSMarcel Moolenaar 	}
51280f1c58bSMarcel Moolenaar 
513879e0604SMateusz Guzik 	if ((flags & TOTTY) && tp != NULL && !KERNEL_PANICKED())
514bc093719SEd Schouten 		tty_putchar(tp, c);
515d42a4eb5SKenneth D. Merry 
51680f1c58bSMarcel Moolenaar 	if ((flags & (TOCONS | TOLOG)) && c != '\0')
517d42a4eb5SKenneth D. Merry 		putbuf(c, ap);
518791d77e0SPoul-Henning Kamp }
519791d77e0SPoul-Henning Kamp 
520791d77e0SPoul-Henning Kamp /*
521791d77e0SPoul-Henning Kamp  * Scaled down version of sprintf(3).
522791d77e0SPoul-Henning Kamp  */
523791d77e0SPoul-Henning Kamp int
524791d77e0SPoul-Henning Kamp sprintf(char *buf, const char *cfmt, ...)
525791d77e0SPoul-Henning Kamp {
526791d77e0SPoul-Henning Kamp 	int retval;
527791d77e0SPoul-Henning Kamp 	va_list ap;
528791d77e0SPoul-Henning Kamp 
529791d77e0SPoul-Henning Kamp 	va_start(ap, cfmt);
530791d77e0SPoul-Henning Kamp 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
531fe96d47dSPoul-Henning Kamp 	buf[retval] = '\0';
532791d77e0SPoul-Henning Kamp 	va_end(ap);
53358a24f79SPoul-Henning Kamp 	return (retval);
534791d77e0SPoul-Henning Kamp }
535791d77e0SPoul-Henning Kamp 
536791d77e0SPoul-Henning Kamp /*
53799237364SAndrey A. Chernov  * Scaled down version of vsprintf(3).
53899237364SAndrey A. Chernov  */
53999237364SAndrey A. Chernov int
54099237364SAndrey A. Chernov vsprintf(char *buf, const char *cfmt, va_list ap)
54199237364SAndrey A. Chernov {
54299237364SAndrey A. Chernov 	int retval;
54399237364SAndrey A. Chernov 
54499237364SAndrey A. Chernov 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
54599237364SAndrey A. Chernov 	buf[retval] = '\0';
54658a24f79SPoul-Henning Kamp 	return (retval);
54799237364SAndrey A. Chernov }
54899237364SAndrey A. Chernov 
54999237364SAndrey A. Chernov /*
5508245f3f5SArchie Cobbs  * Scaled down version of snprintf(3).
5518245f3f5SArchie Cobbs  */
5528245f3f5SArchie Cobbs int
5538245f3f5SArchie Cobbs snprintf(char *str, size_t size, const char *format, ...)
5548245f3f5SArchie Cobbs {
5558245f3f5SArchie Cobbs 	int retval;
5568245f3f5SArchie Cobbs 	va_list ap;
5578245f3f5SArchie Cobbs 
5588245f3f5SArchie Cobbs 	va_start(ap, format);
5598245f3f5SArchie Cobbs 	retval = vsnprintf(str, size, format, ap);
5608245f3f5SArchie Cobbs 	va_end(ap);
5618245f3f5SArchie Cobbs 	return(retval);
5628245f3f5SArchie Cobbs }
5638245f3f5SArchie Cobbs 
5648245f3f5SArchie Cobbs /*
5658245f3f5SArchie Cobbs  * Scaled down version of vsnprintf(3).
5668245f3f5SArchie Cobbs  */
5678245f3f5SArchie Cobbs int
5688245f3f5SArchie Cobbs vsnprintf(char *str, size_t size, const char *format, va_list ap)
5698245f3f5SArchie Cobbs {
5708245f3f5SArchie Cobbs 	struct snprintf_arg info;
5718245f3f5SArchie Cobbs 	int retval;
5728245f3f5SArchie Cobbs 
5738245f3f5SArchie Cobbs 	info.str = str;
5748245f3f5SArchie Cobbs 	info.remain = size;
5758245f3f5SArchie Cobbs 	retval = kvprintf(format, snprintf_func, &info, 10, ap);
5768245f3f5SArchie Cobbs 	if (info.remain >= 1)
5778245f3f5SArchie Cobbs 		*info.str++ = '\0';
57858a24f79SPoul-Henning Kamp 	return (retval);
5798245f3f5SArchie Cobbs }
5808245f3f5SArchie Cobbs 
5818751a8c7SPoul-Henning Kamp /*
5828751a8c7SPoul-Henning Kamp  * Kernel version which takes radix argument vsnprintf(3).
5838751a8c7SPoul-Henning Kamp  */
5848751a8c7SPoul-Henning Kamp int
5858751a8c7SPoul-Henning Kamp vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
5868751a8c7SPoul-Henning Kamp {
5878751a8c7SPoul-Henning Kamp 	struct snprintf_arg info;
5888751a8c7SPoul-Henning Kamp 	int retval;
5898751a8c7SPoul-Henning Kamp 
5908751a8c7SPoul-Henning Kamp 	info.str = str;
5918751a8c7SPoul-Henning Kamp 	info.remain = size;
5928751a8c7SPoul-Henning Kamp 	retval = kvprintf(format, snprintf_func, &info, radix, ap);
5938751a8c7SPoul-Henning Kamp 	if (info.remain >= 1)
5948751a8c7SPoul-Henning Kamp 		*info.str++ = '\0';
5958751a8c7SPoul-Henning Kamp 	return (retval);
5968751a8c7SPoul-Henning Kamp }
5978751a8c7SPoul-Henning Kamp 
5988245f3f5SArchie Cobbs static void
5998245f3f5SArchie Cobbs snprintf_func(int ch, void *arg)
6008245f3f5SArchie Cobbs {
6018245f3f5SArchie Cobbs 	struct snprintf_arg *const info = arg;
6028245f3f5SArchie Cobbs 
6038245f3f5SArchie Cobbs 	if (info->remain >= 2) {
6048245f3f5SArchie Cobbs 		*info->str++ = ch;
6058245f3f5SArchie Cobbs 		info->remain--;
6068245f3f5SArchie Cobbs 	}
6078245f3f5SArchie Cobbs }
6088245f3f5SArchie Cobbs 
6098245f3f5SArchie Cobbs /*
61082941964SPeter Wemm  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
61105292ba2SArchie Cobbs  * order; return an optional length and a pointer to the last character
61205292ba2SArchie Cobbs  * written in the buffer (i.e., the first character of the string).
61305292ba2SArchie Cobbs  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
614791d77e0SPoul-Henning Kamp  */
615791d77e0SPoul-Henning Kamp static char *
6160d84d9ebSJung-uk Kim ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
61705292ba2SArchie Cobbs {
6180d84d9ebSJung-uk Kim 	char *p, c;
619791d77e0SPoul-Henning Kamp 
62005292ba2SArchie Cobbs 	p = nbuf;
621ad4f8dbdSArchie Cobbs 	*p = '\0';
622791d77e0SPoul-Henning Kamp 	do {
6230d84d9ebSJung-uk Kim 		c = hex2ascii(num % base);
6240d84d9ebSJung-uk Kim 		*++p = upper ? toupper(c) : c;
6253b1f7e7dSDag-Erling Smørgrav 	} while (num /= base);
6267d921a01SPeter Wemm 	if (lenp)
6277d921a01SPeter Wemm 		*lenp = p - nbuf;
6287d921a01SPeter Wemm 	return (p);
6297d921a01SPeter Wemm }
630791d77e0SPoul-Henning Kamp 
631df8bae1dSRodney W. Grimes /*
632df8bae1dSRodney W. Grimes  * Scaled down version of printf(3).
633df8bae1dSRodney W. Grimes  *
634df8bae1dSRodney W. Grimes  * Two additional formats:
635df8bae1dSRodney W. Grimes  *
636df8bae1dSRodney W. Grimes  * The format %b is supported to decode error registers.
637df8bae1dSRodney W. Grimes  * Its usage is:
638df8bae1dSRodney W. Grimes  *
639df8bae1dSRodney W. Grimes  *	printf("reg=%b\n", regval, "<base><arg>*");
640df8bae1dSRodney W. Grimes  *
641df8bae1dSRodney W. Grimes  * where <base> is the output base expressed as a control character, e.g.
642df8bae1dSRodney W. Grimes  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
643df8bae1dSRodney W. Grimes  * the first of which gives the bit number to be inspected (origin 1), and
644df8bae1dSRodney W. Grimes  * the next characters (up to a control character, i.e. a character <= 32),
645df8bae1dSRodney W. Grimes  * give the name of the register.  Thus:
646df8bae1dSRodney W. Grimes  *
647c5f282daSAlexey Dokuchaev  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
648df8bae1dSRodney W. Grimes  *
649df8bae1dSRodney W. Grimes  * would produce output:
650df8bae1dSRodney W. Grimes  *
651df8bae1dSRodney W. Grimes  *	reg=3<BITTWO,BITONE>
652df8bae1dSRodney W. Grimes  *
653120f0783SPoul-Henning Kamp  * XXX:  %D  -- Hexdump, takes pointer and separator string:
654120f0783SPoul-Henning Kamp  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
655120f0783SPoul-Henning Kamp  *		("%*D", len, ptr, " " -> XX XX XX XX ...
656df8bae1dSRodney W. Grimes  */
657791d77e0SPoul-Henning Kamp int
658791d77e0SPoul-Henning Kamp kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
659df8bae1dSRodney W. Grimes {
660791d77e0SPoul-Henning Kamp #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
661ad4f8dbdSArchie Cobbs 	char nbuf[MAXNBUF];
6623b1f7e7dSDag-Erling Smørgrav 	char *d;
6633b1f7e7dSDag-Erling Smørgrav 	const char *p, *percent, *q;
664120f0783SPoul-Henning Kamp 	u_char *up;
665791d77e0SPoul-Henning Kamp 	int ch, n;
6663b1f7e7dSDag-Erling Smørgrav 	uintmax_t num;
6677d921a01SPeter Wemm 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
66832869e71SNate Lawson 	int cflag, hflag, jflag, tflag, zflag;
669808a9c86SRyan Libby 	int bconv, dwidth, upper;
670df8bae1dSRodney W. Grimes 	char padc;
6711e7d2c47SPoul-Henning Kamp 	int stop = 0, retval = 0;
672791d77e0SPoul-Henning Kamp 
6733b1f7e7dSDag-Erling Smørgrav 	num = 0;
674b2037136SMatt Macy 	q = NULL;
675fe96d47dSPoul-Henning Kamp 	if (!func)
676791d77e0SPoul-Henning Kamp 		d = (char *) arg;
677791d77e0SPoul-Henning Kamp 	else
678fe96d47dSPoul-Henning Kamp 		d = NULL;
6798f5067baSDavid Greenman 
6808f5067baSDavid Greenman 	if (fmt == NULL)
6812336b9d7SBruce Evans 		fmt = "(fmt null)\n";
682b4b2f81eSPoul-Henning Kamp 
683120f0783SPoul-Henning Kamp 	if (radix < 2 || radix > 36)
684b4b2f81eSPoul-Henning Kamp 		radix = 10;
685b4b2f81eSPoul-Henning Kamp 
686df8bae1dSRodney W. Grimes 	for (;;) {
687df8bae1dSRodney W. Grimes 		padc = ' ';
688df8bae1dSRodney W. Grimes 		width = 0;
6891e7d2c47SPoul-Henning Kamp 		while ((ch = (u_char)*fmt++) != '%' || stop) {
690df8bae1dSRodney W. Grimes 			if (ch == '\0')
69158a24f79SPoul-Henning Kamp 				return (retval);
692791d77e0SPoul-Henning Kamp 			PCHAR(ch);
693df8bae1dSRodney W. Grimes 		}
6943b1f7e7dSDag-Erling Smørgrav 		percent = fmt - 1;
6957d921a01SPeter Wemm 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
696808a9c86SRyan Libby 		sign = 0; dot = 0; bconv = 0; dwidth = 0; upper = 0;
69732869e71SNate Lawson 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
698e0c95ed9SBruce Evans reswitch:	switch (ch = (u_char)*fmt++) {
6994830092aSPoul-Henning Kamp 		case '.':
7004830092aSPoul-Henning Kamp 			dot = 1;
7014830092aSPoul-Henning Kamp 			goto reswitch;
702791d77e0SPoul-Henning Kamp 		case '#':
703791d77e0SPoul-Henning Kamp 			sharpflag = 1;
704791d77e0SPoul-Henning Kamp 			goto reswitch;
705791d77e0SPoul-Henning Kamp 		case '+':
706791d77e0SPoul-Henning Kamp 			sign = 1;
707791d77e0SPoul-Henning Kamp 			goto reswitch;
708791d77e0SPoul-Henning Kamp 		case '-':
709791d77e0SPoul-Henning Kamp 			ladjust = 1;
710791d77e0SPoul-Henning Kamp 			goto reswitch;
711791d77e0SPoul-Henning Kamp 		case '%':
712791d77e0SPoul-Henning Kamp 			PCHAR(ch);
713791d77e0SPoul-Henning Kamp 			break;
714791d77e0SPoul-Henning Kamp 		case '*':
715ed71c342SPoul-Henning Kamp 			if (!dot) {
716791d77e0SPoul-Henning Kamp 				width = va_arg(ap, int);
717791d77e0SPoul-Henning Kamp 				if (width < 0) {
718791d77e0SPoul-Henning Kamp 					ladjust = !ladjust;
719791d77e0SPoul-Henning Kamp 					width = -width;
720791d77e0SPoul-Henning Kamp 				}
721ed71c342SPoul-Henning Kamp 			} else {
722ed71c342SPoul-Henning Kamp 				dwidth = va_arg(ap, int);
723ed71c342SPoul-Henning Kamp 			}
724791d77e0SPoul-Henning Kamp 			goto reswitch;
725df8bae1dSRodney W. Grimes 		case '0':
7264f20e4b1SPoul-Henning Kamp 			if (!dot) {
727df8bae1dSRodney W. Grimes 				padc = '0';
728df8bae1dSRodney W. Grimes 				goto reswitch;
7294f20e4b1SPoul-Henning Kamp 			}
7309295517aSMark Johnston 			/* FALLTHROUGH */
731df8bae1dSRodney W. Grimes 		case '1': case '2': case '3': case '4':
732df8bae1dSRodney W. Grimes 		case '5': case '6': case '7': case '8': case '9':
7334f20e4b1SPoul-Henning Kamp 				for (n = 0;; ++fmt) {
7344f20e4b1SPoul-Henning Kamp 					n = n * 10 + ch - '0';
735df8bae1dSRodney W. Grimes 					ch = *fmt;
736df8bae1dSRodney W. Grimes 					if (ch < '0' || ch > '9')
737df8bae1dSRodney W. Grimes 						break;
738df8bae1dSRodney W. Grimes 				}
7394f20e4b1SPoul-Henning Kamp 			if (dot)
7404f20e4b1SPoul-Henning Kamp 				dwidth = n;
7414f20e4b1SPoul-Henning Kamp 			else
7424f20e4b1SPoul-Henning Kamp 				width = n;
743df8bae1dSRodney W. Grimes 			goto reswitch;
744df8bae1dSRodney W. Grimes 		case 'b':
745808a9c86SRyan Libby 			ladjust = 1;
746808a9c86SRyan Libby 			bconv = 1;
747808a9c86SRyan Libby 			goto handle_nosign;
748df8bae1dSRodney W. Grimes 		case 'c':
749dd6ea7f7SConrad Meyer 			width -= 1;
750dd6ea7f7SConrad Meyer 
751dd6ea7f7SConrad Meyer 			if (!ladjust && width > 0)
752dd6ea7f7SConrad Meyer 				while (width--)
753dd6ea7f7SConrad Meyer 					PCHAR(padc);
754791d77e0SPoul-Henning Kamp 			PCHAR(va_arg(ap, int));
755dd6ea7f7SConrad Meyer 			if (ladjust && width > 0)
756dd6ea7f7SConrad Meyer 				while (width--)
757dd6ea7f7SConrad Meyer 					PCHAR(padc);
758df8bae1dSRodney W. Grimes 			break;
759120f0783SPoul-Henning Kamp 		case 'D':
760120f0783SPoul-Henning Kamp 			up = va_arg(ap, u_char *);
761120f0783SPoul-Henning Kamp 			p = va_arg(ap, char *);
762120f0783SPoul-Henning Kamp 			if (!width)
763120f0783SPoul-Henning Kamp 				width = 16;
764120f0783SPoul-Henning Kamp 			while(width--) {
765120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up >> 4));
766120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up & 0x0f));
767120f0783SPoul-Henning Kamp 				up++;
768120f0783SPoul-Henning Kamp 				if (width)
769120f0783SPoul-Henning Kamp 					for (q=p;*q;q++)
770120f0783SPoul-Henning Kamp 						PCHAR(*q);
771120f0783SPoul-Henning Kamp 			}
772120f0783SPoul-Henning Kamp 			break;
773df8bae1dSRodney W. Grimes 		case 'd':
774e0b74464SWarner Losh 		case 'i':
775df8bae1dSRodney W. Grimes 			base = 10;
7763b1f7e7dSDag-Erling Smørgrav 			sign = 1;
7773b1f7e7dSDag-Erling Smørgrav 			goto handle_sign;
77832869e71SNate Lawson 		case 'h':
77932869e71SNate Lawson 			if (hflag) {
78032869e71SNate Lawson 				hflag = 0;
78132869e71SNate Lawson 				cflag = 1;
78232869e71SNate Lawson 			} else
78332869e71SNate Lawson 				hflag = 1;
78432869e71SNate Lawson 			goto reswitch;
7853b1f7e7dSDag-Erling Smørgrav 		case 'j':
7863b1f7e7dSDag-Erling Smørgrav 			jflag = 1;
7873b1f7e7dSDag-Erling Smørgrav 			goto reswitch;
788791d77e0SPoul-Henning Kamp 		case 'l':
789301ca4ffSBrian Feldman 			if (lflag) {
790301ca4ffSBrian Feldman 				lflag = 0;
791301ca4ffSBrian Feldman 				qflag = 1;
792301ca4ffSBrian Feldman 			} else
793791d77e0SPoul-Henning Kamp 				lflag = 1;
794791d77e0SPoul-Henning Kamp 			goto reswitch;
7953b1f7e7dSDag-Erling Smørgrav 		case 'n':
796937b352eSEd Maste 			/*
797937b352eSEd Maste 			 * We do not support %n in kernel, but consume the
798937b352eSEd Maste 			 * argument.
799937b352eSEd Maste 			 */
8003b1f7e7dSDag-Erling Smørgrav 			if (jflag)
801937b352eSEd Maste 				(void)va_arg(ap, intmax_t *);
8023b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
803937b352eSEd Maste 				(void)va_arg(ap, quad_t *);
8047d921a01SPeter Wemm 			else if (lflag)
805937b352eSEd Maste 				(void)va_arg(ap, long *);
8064578a2e6SMaxime Henrion 			else if (zflag)
807937b352eSEd Maste 				(void)va_arg(ap, size_t *);
80832869e71SNate Lawson 			else if (hflag)
809937b352eSEd Maste 				(void)va_arg(ap, short *);
81032869e71SNate Lawson 			else if (cflag)
811937b352eSEd Maste 				(void)va_arg(ap, char *);
8127d921a01SPeter Wemm 			else
813937b352eSEd Maste 				(void)va_arg(ap, int *);
8143b1f7e7dSDag-Erling Smørgrav 			break;
8153b1f7e7dSDag-Erling Smørgrav 		case 'o':
816df8bae1dSRodney W. Grimes 			base = 8;
8173b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
81812d17f65SPoul-Henning Kamp 		case 'p':
81912d17f65SPoul-Henning Kamp 			base = 16;
820c41141b0SBruce Evans 			sharpflag = (width == 0);
8213b1f7e7dSDag-Erling Smørgrav 			sign = 0;
8223b1f7e7dSDag-Erling Smørgrav 			num = (uintptr_t)va_arg(ap, void *);
8233b1f7e7dSDag-Erling Smørgrav 			goto number;
8247d921a01SPeter Wemm 		case 'q':
8257d921a01SPeter Wemm 			qflag = 1;
8267d921a01SPeter Wemm 			goto reswitch;
827e0c38587SBruce Evans 		case 'r':
828e0c38587SBruce Evans 			base = radix;
8293b1f7e7dSDag-Erling Smørgrav 			if (sign)
8303b1f7e7dSDag-Erling Smørgrav 				goto handle_sign;
8313b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
832791d77e0SPoul-Henning Kamp 		case 's':
833791d77e0SPoul-Henning Kamp 			p = va_arg(ap, char *);
834791d77e0SPoul-Henning Kamp 			if (p == NULL)
835791d77e0SPoul-Henning Kamp 				p = "(null)";
8364830092aSPoul-Henning Kamp 			if (!dot)
8374830092aSPoul-Henning Kamp 				n = strlen (p);
8384830092aSPoul-Henning Kamp 			else
8394f20e4b1SPoul-Henning Kamp 				for (n = 0; n < dwidth && p[n]; n++)
8404830092aSPoul-Henning Kamp 					continue;
8414f20e4b1SPoul-Henning Kamp 
8424830092aSPoul-Henning Kamp 			width -= n;
8434f20e4b1SPoul-Henning Kamp 
844791d77e0SPoul-Henning Kamp 			if (!ladjust && width > 0)
845791d77e0SPoul-Henning Kamp 				while (width--)
846791d77e0SPoul-Henning Kamp 					PCHAR(padc);
8474830092aSPoul-Henning Kamp 			while (n--)
848791d77e0SPoul-Henning Kamp 				PCHAR(*p++);
849791d77e0SPoul-Henning Kamp 			if (ladjust && width > 0)
850791d77e0SPoul-Henning Kamp 				while (width--)
851791d77e0SPoul-Henning Kamp 					PCHAR(padc);
852791d77e0SPoul-Henning Kamp 			break;
8532bb95458SMaxime Henrion 		case 't':
8542bb95458SMaxime Henrion 			tflag = 1;
8552bb95458SMaxime Henrion 			goto reswitch;
856f53dbe97SBruce Evans 		case 'u':
857f53dbe97SBruce Evans 			base = 10;
8583b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
859aa998012SMike Smith 		case 'X':
8600d84d9ebSJung-uk Kim 			upper = 1;
861679e4cdaSMarius Strobl 			/* FALLTHROUGH */
8620d84d9ebSJung-uk Kim 		case 'x':
863df8bae1dSRodney W. Grimes 			base = 16;
8643b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
8654578a2e6SMaxime Henrion 		case 'y':
866e0c38587SBruce Evans 			base = 16;
86785594430SJohn Baldwin 			sign = 1;
8683b1f7e7dSDag-Erling Smørgrav 			goto handle_sign;
8694578a2e6SMaxime Henrion 		case 'z':
8704578a2e6SMaxime Henrion 			zflag = 1;
8714578a2e6SMaxime Henrion 			goto reswitch;
8723b1f7e7dSDag-Erling Smørgrav handle_nosign:
8733b1f7e7dSDag-Erling Smørgrav 			sign = 0;
8743b1f7e7dSDag-Erling Smørgrav 			if (jflag)
8753b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, uintmax_t);
8763b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
8773b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_quad_t);
8782bb95458SMaxime Henrion 			else if (tflag)
8792bb95458SMaxime Henrion 				num = va_arg(ap, ptrdiff_t);
8803b1f7e7dSDag-Erling Smørgrav 			else if (lflag)
8813b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_long);
8824578a2e6SMaxime Henrion 			else if (zflag)
8834578a2e6SMaxime Henrion 				num = va_arg(ap, size_t);
88432869e71SNate Lawson 			else if (hflag)
88532869e71SNate Lawson 				num = (u_short)va_arg(ap, int);
88632869e71SNate Lawson 			else if (cflag)
88732869e71SNate Lawson 				num = (u_char)va_arg(ap, int);
8883b1f7e7dSDag-Erling Smørgrav 			else
8893b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_int);
890808a9c86SRyan Libby 			if (bconv) {
891808a9c86SRyan Libby 				q = va_arg(ap, char *);
892808a9c86SRyan Libby 				base = *q++;
893808a9c86SRyan Libby 			}
894e0c38587SBruce Evans 			goto number;
8953b1f7e7dSDag-Erling Smørgrav handle_sign:
8963b1f7e7dSDag-Erling Smørgrav 			if (jflag)
8973b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, intmax_t);
8983b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
8993b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, quad_t);
9002bb95458SMaxime Henrion 			else if (tflag)
9012bb95458SMaxime Henrion 				num = va_arg(ap, ptrdiff_t);
9023b1f7e7dSDag-Erling Smørgrav 			else if (lflag)
9033b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, long);
9044578a2e6SMaxime Henrion 			else if (zflag)
905e1088cdcSXin LI 				num = va_arg(ap, ssize_t);
90632869e71SNate Lawson 			else if (hflag)
90732869e71SNate Lawson 				num = (short)va_arg(ap, int);
90832869e71SNate Lawson 			else if (cflag)
90932869e71SNate Lawson 				num = (char)va_arg(ap, int);
9103b1f7e7dSDag-Erling Smørgrav 			else
9113b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, int);
9127d921a01SPeter Wemm number:
9133b1f7e7dSDag-Erling Smørgrav 			if (sign && (intmax_t)num < 0) {
9147d921a01SPeter Wemm 				neg = 1;
9153b1f7e7dSDag-Erling Smørgrav 				num = -(intmax_t)num;
9167d921a01SPeter Wemm 			}
9174624e08aSJung-uk Kim 			p = ksprintn(nbuf, num, base, &n, upper);
9184624e08aSJung-uk Kim 			tmp = 0;
9193b1f7e7dSDag-Erling Smørgrav 			if (sharpflag && num != 0) {
920791d77e0SPoul-Henning Kamp 				if (base == 8)
921791d77e0SPoul-Henning Kamp 					tmp++;
922791d77e0SPoul-Henning Kamp 				else if (base == 16)
923791d77e0SPoul-Henning Kamp 					tmp += 2;
924791d77e0SPoul-Henning Kamp 			}
925791d77e0SPoul-Henning Kamp 			if (neg)
926791d77e0SPoul-Henning Kamp 				tmp++;
927791d77e0SPoul-Henning Kamp 
9284624e08aSJung-uk Kim 			if (!ladjust && padc == '0')
9294624e08aSJung-uk Kim 				dwidth = width - tmp;
9304a82f108SJung-uk Kim 			width -= tmp + imax(dwidth, n);
9314624e08aSJung-uk Kim 			dwidth -= n;
9324624e08aSJung-uk Kim 			if (!ladjust)
9334624e08aSJung-uk Kim 				while (width-- > 0)
9344624e08aSJung-uk Kim 					PCHAR(' ');
935791d77e0SPoul-Henning Kamp 			if (neg)
936791d77e0SPoul-Henning Kamp 				PCHAR('-');
9373b1f7e7dSDag-Erling Smørgrav 			if (sharpflag && num != 0) {
938791d77e0SPoul-Henning Kamp 				if (base == 8) {
939791d77e0SPoul-Henning Kamp 					PCHAR('0');
940791d77e0SPoul-Henning Kamp 				} else if (base == 16) {
941791d77e0SPoul-Henning Kamp 					PCHAR('0');
942791d77e0SPoul-Henning Kamp 					PCHAR('x');
943791d77e0SPoul-Henning Kamp 				}
944791d77e0SPoul-Henning Kamp 			}
9454624e08aSJung-uk Kim 			while (dwidth-- > 0)
9464624e08aSJung-uk Kim 				PCHAR('0');
947791d77e0SPoul-Henning Kamp 
948797f2d22SPoul-Henning Kamp 			while (*p)
949791d77e0SPoul-Henning Kamp 				PCHAR(*p--);
950791d77e0SPoul-Henning Kamp 
951808a9c86SRyan Libby 			if (bconv && num != 0) {
952808a9c86SRyan Libby 				/* %b conversion flag format. */
953808a9c86SRyan Libby 				tmp = retval;
954808a9c86SRyan Libby 				while (*q) {
955808a9c86SRyan Libby 					n = *q++;
956808a9c86SRyan Libby 					if (num & (1 << (n - 1))) {
957808a9c86SRyan Libby 						PCHAR(retval != tmp ?
958808a9c86SRyan Libby 						    ',' : '<');
959808a9c86SRyan Libby 						for (; (n = *q) > ' '; ++q)
960808a9c86SRyan Libby 							PCHAR(n);
961808a9c86SRyan Libby 					} else
962808a9c86SRyan Libby 						for (; *q > ' '; ++q)
963808a9c86SRyan Libby 							continue;
964808a9c86SRyan Libby 				}
965808a9c86SRyan Libby 				if (retval != tmp) {
966808a9c86SRyan Libby 					PCHAR('>');
967808a9c86SRyan Libby 					width -= retval - tmp;
968808a9c86SRyan Libby 				}
969808a9c86SRyan Libby 			}
970808a9c86SRyan Libby 
9714624e08aSJung-uk Kim 			if (ladjust)
9724624e08aSJung-uk Kim 				while (width-- > 0)
9734624e08aSJung-uk Kim 					PCHAR(' ');
974791d77e0SPoul-Henning Kamp 
975df8bae1dSRodney W. Grimes 			break;
976df8bae1dSRodney W. Grimes 		default:
9773b1f7e7dSDag-Erling Smørgrav 			while (percent < fmt)
9783b1f7e7dSDag-Erling Smørgrav 				PCHAR(*percent++);
9791e7d2c47SPoul-Henning Kamp 			/*
9802809a6dfSBryan Drewery 			 * Since we ignore a formatting argument it is no
9811e7d2c47SPoul-Henning Kamp 			 * longer safe to obey the remaining formatting
9821e7d2c47SPoul-Henning Kamp 			 * arguments as the arguments will no longer match
9831e7d2c47SPoul-Henning Kamp 			 * the format specs.
9841e7d2c47SPoul-Henning Kamp 			 */
9851e7d2c47SPoul-Henning Kamp 			stop = 1;
986791d77e0SPoul-Henning Kamp 			break;
987df8bae1dSRodney W. Grimes 		}
988df8bae1dSRodney W. Grimes 	}
989791d77e0SPoul-Henning Kamp #undef PCHAR
990df8bae1dSRodney W. Grimes }
991df8bae1dSRodney W. Grimes 
992df8bae1dSRodney W. Grimes /*
993e2a09b26SPoul-Henning Kamp  * Put character in log buffer with a particular priority.
994df8bae1dSRodney W. Grimes  */
995df8bae1dSRodney W. Grimes static void
996e2a09b26SPoul-Henning Kamp msglogchar(int c, int pri)
997e2a09b26SPoul-Henning Kamp {
998e2a09b26SPoul-Henning Kamp 	static int lastpri = -1;
999e2a09b26SPoul-Henning Kamp 	static int dangling;
1000e2a09b26SPoul-Henning Kamp 	char nbuf[MAXNBUF];
1001e2a09b26SPoul-Henning Kamp 	char *p;
1002e2a09b26SPoul-Henning Kamp 
1003e2a09b26SPoul-Henning Kamp 	if (!msgbufmapped)
1004e2a09b26SPoul-Henning Kamp 		return;
1005e2a09b26SPoul-Henning Kamp 	if (c == '\0' || c == '\r')
1006e2a09b26SPoul-Henning Kamp 		return;
1007e2a09b26SPoul-Henning Kamp 	if (pri != -1 && pri != lastpri) {
1008e2a09b26SPoul-Henning Kamp 		if (dangling) {
10094784a469SIan Dowse 			msgbuf_addchar(msgbufp, '\n');
1010e2a09b26SPoul-Henning Kamp 			dangling = 0;
1011e2a09b26SPoul-Henning Kamp 		}
10124784a469SIan Dowse 		msgbuf_addchar(msgbufp, '<');
10130d84d9ebSJung-uk Kim 		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL, 0); *p;)
10144784a469SIan Dowse 			msgbuf_addchar(msgbufp, *p--);
10154784a469SIan Dowse 		msgbuf_addchar(msgbufp, '>');
1016e2a09b26SPoul-Henning Kamp 		lastpri = pri;
1017e2a09b26SPoul-Henning Kamp 	}
10184784a469SIan Dowse 	msgbuf_addchar(msgbufp, c);
1019e2a09b26SPoul-Henning Kamp 	if (c == '\n') {
1020e2a09b26SPoul-Henning Kamp 		dangling = 0;
1021e2a09b26SPoul-Henning Kamp 		lastpri = -1;
1022e2a09b26SPoul-Henning Kamp 	} else {
1023e2a09b26SPoul-Henning Kamp 		dangling = 1;
1024e2a09b26SPoul-Henning Kamp 	}
1025e2a09b26SPoul-Henning Kamp }
1026e2a09b26SPoul-Henning Kamp 
1027d42a4eb5SKenneth D. Merry static void
1028d42a4eb5SKenneth D. Merry msglogstr(char *str, int pri, int filter_cr)
1029d42a4eb5SKenneth D. Merry {
1030d42a4eb5SKenneth D. Merry 	if (!msgbufmapped)
1031d42a4eb5SKenneth D. Merry 		return;
1032d42a4eb5SKenneth D. Merry 
1033d42a4eb5SKenneth D. Merry 	msgbuf_addstr(msgbufp, pri, str, filter_cr);
1034d42a4eb5SKenneth D. Merry }
1035d42a4eb5SKenneth D. Merry 
1036e796e00dSPoul-Henning Kamp void
103701ee4395SThomas Moestl msgbufinit(void *ptr, int size)
1038e796e00dSPoul-Henning Kamp {
1039e796e00dSPoul-Henning Kamp 	char *cp;
10400915d9d0SKyle Evans 	static struct msgbuf *oldp = NULL;
1041170bc291SKyle Evans 	bool print_boot_tag;
1042e796e00dSPoul-Henning Kamp 
10439d6ae1e3SColin Percival 	TSENTER();
1044cca8f980SIan Dowse 	size -= sizeof(*msgbufp);
1045e796e00dSPoul-Henning Kamp 	cp = (char *)ptr;
1046170bc291SKyle Evans 	print_boot_tag = !msgbufmapped;
10472a4650ccSKyle Evans 	/* Attempt to fetch kern.boot_tag tunable on first mapping */
10482a4650ccSKyle Evans 	if (!msgbufmapped)
10492a4650ccSKyle Evans 		TUNABLE_STR_FETCH("kern.boot_tag", current_boot_tag,
1050240fcda1SKyle Evans 		    sizeof(current_boot_tag));
1051cca8f980SIan Dowse 	msgbufp = (struct msgbuf *)(cp + size);
10524784a469SIan Dowse 	msgbuf_reinit(msgbufp, cp, size);
1053eb9d435aSJonathan Lemon 	if (msgbufmapped && oldp != msgbufp)
10544784a469SIan Dowse 		msgbuf_copy(oldp, msgbufp);
105521aa6e83SKyle Evans 	msgbufmapped = true;
105645625675SKyle Evans 	if (print_boot_tag && *current_boot_tag != '\0')
1057170bc291SKyle Evans 		printf("%s\n", current_boot_tag);
1058eb9d435aSJonathan Lemon 	oldp = msgbufp;
10599d6ae1e3SColin Percival 	TSEXIT();
1060e796e00dSPoul-Henning Kamp }
1061e796e00dSPoul-Henning Kamp 
1062948d3d94SThomas Moestl /* Sysctls for accessing/clearing the msgbuf */
1063948d3d94SThomas Moestl static int
1064948d3d94SThomas Moestl sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
1065948d3d94SThomas Moestl {
1066c999e348SGleb Smirnoff 	char buf[128], *bp;
10674784a469SIan Dowse 	u_int seq;
10684784a469SIan Dowse 	int error, len;
1069c999e348SGleb Smirnoff 	bool wrap;
1070948d3d94SThomas Moestl 
1071acd3428bSRobert Watson 	error = priv_check(req->td, PRIV_MSGBUF);
10726f3933faSRobert Watson 	if (error)
10736f3933faSRobert Watson 		return (error);
10746f3933faSRobert Watson 
10754784a469SIan Dowse 	/* Read the whole buffer, one chunk at a time. */
1076ca1d2f65SEd Schouten 	mtx_lock(&msgbuf_lock);
10774784a469SIan Dowse 	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
1078c999e348SGleb Smirnoff 	wrap = (seq != 0);
1079ca1d2f65SEd Schouten 	for (;;) {
1080ca1d2f65SEd Schouten 		len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
1081ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
1082ca1d2f65SEd Schouten 		if (len == 0)
1083e5197e3aSIan Lepore 			return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
1084c999e348SGleb Smirnoff 		if (wrap) {
1085c999e348SGleb Smirnoff 			/* Skip the first line, as it is probably incomplete. */
1086c999e348SGleb Smirnoff 			bp = memchr(buf, '\n', len);
1087c999e348SGleb Smirnoff 			if (bp == NULL) {
1088c999e348SGleb Smirnoff 				mtx_lock(&msgbuf_lock);
1089c999e348SGleb Smirnoff 				continue;
1090c999e348SGleb Smirnoff 			}
1091c999e348SGleb Smirnoff 			wrap = false;
1092c999e348SGleb Smirnoff 			bp++;
1093c999e348SGleb Smirnoff 			len -= bp - buf;
1094c999e348SGleb Smirnoff 			if (len == 0) {
1095c999e348SGleb Smirnoff 				mtx_lock(&msgbuf_lock);
1096c999e348SGleb Smirnoff 				continue;
1097c999e348SGleb Smirnoff 			}
1098c999e348SGleb Smirnoff 		} else
1099c999e348SGleb Smirnoff 			bp = buf;
1100c999e348SGleb Smirnoff 		error = sysctl_handle_opaque(oidp, bp, len, req);
1101948d3d94SThomas Moestl 		if (error)
1102948d3d94SThomas Moestl 			return (error);
1103ca1d2f65SEd Schouten 
1104ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
1105948d3d94SThomas Moestl 	}
1106948d3d94SThomas Moestl }
1107948d3d94SThomas Moestl 
1108ca1d2f65SEd Schouten SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
1109ca1d2f65SEd Schouten     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
11104592c621SWarner Losh     NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
1111948d3d94SThomas Moestl 
11124784a469SIan Dowse static int msgbuf_clearflag;
1113948d3d94SThomas Moestl 
1114948d3d94SThomas Moestl static int
1115948d3d94SThomas Moestl sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
1116948d3d94SThomas Moestl {
1117948d3d94SThomas Moestl 	int error;
1118948d3d94SThomas Moestl 	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1119948d3d94SThomas Moestl 	if (!error && req->newptr) {
1120ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
11214784a469SIan Dowse 		msgbuf_clear(msgbufp);
1122ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
11234784a469SIan Dowse 		msgbuf_clearflag = 0;
1124948d3d94SThomas Moestl 	}
1125948d3d94SThomas Moestl 	return (error);
1126948d3d94SThomas Moestl }
1127948d3d94SThomas Moestl 
1128948d3d94SThomas Moestl SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
1129ca1d2f65SEd Schouten     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE,
1130ca1d2f65SEd Schouten     &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I",
1131ca1d2f65SEd Schouten     "Clear kernel message buffer");
1132948d3d94SThomas Moestl 
1133e796e00dSPoul-Henning Kamp #ifdef DDB
1134e796e00dSPoul-Henning Kamp 
1135c84c5e00SMitchell Horne DB_SHOW_COMMAND_FLAGS(msgbuf, db_show_msgbuf, DB_CMD_MEMSAFE)
1136e796e00dSPoul-Henning Kamp {
113719e9205aSJohn Baldwin 	int i, j;
1138e796e00dSPoul-Henning Kamp 
1139e796e00dSPoul-Henning Kamp 	if (!msgbufmapped) {
1140e796e00dSPoul-Henning Kamp 		db_printf("msgbuf not mapped yet\n");
1141e796e00dSPoul-Henning Kamp 		return;
1142e796e00dSPoul-Henning Kamp 	}
1143e796e00dSPoul-Henning Kamp 	db_printf("msgbufp = %p\n", msgbufp);
11444784a469SIan Dowse 	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
11454784a469SIan Dowse 	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
11464784a469SIan Dowse 	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
114719e9205aSJohn Baldwin 	for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) {
11484784a469SIan Dowse 		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
1149e796e00dSPoul-Henning Kamp 		db_printf("%c", msgbufp->msg_ptr[j]);
1150e796e00dSPoul-Henning Kamp 	}
1151e796e00dSPoul-Henning Kamp 	db_printf("\n");
1152e796e00dSPoul-Henning Kamp }
1153e796e00dSPoul-Henning Kamp 
1154e796e00dSPoul-Henning Kamp #endif /* DDB */
115577411499SScott Long 
115677411499SScott Long void
115730a1695bSPoul-Henning Kamp hexdump(const void *ptr, int length, const char *hdr, int flags)
115877411499SScott Long {
115977411499SScott Long 	int i, j, k;
116077411499SScott Long 	int cols;
116130a1695bSPoul-Henning Kamp 	const unsigned char *cp;
116277411499SScott Long 	char delim;
116377411499SScott Long 
116477411499SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
116577411499SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
116677411499SScott Long 	else
116777411499SScott Long 		delim = ' ';
116877411499SScott Long 
116977411499SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
117077411499SScott Long 		cols = flags & HD_COLUMN_MASK;
117177411499SScott Long 	else
117277411499SScott Long 		cols = 16;
117377411499SScott Long 
117477411499SScott Long 	cp = ptr;
117577411499SScott Long 	for (i = 0; i < length; i+= cols) {
117677411499SScott Long 		if (hdr != NULL)
117777411499SScott Long 			printf("%s", hdr);
117877411499SScott Long 
117977411499SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
118077411499SScott Long 			printf("%04x  ", i);
118177411499SScott Long 
118277411499SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
118377411499SScott Long 			for (j = 0; j < cols; j++) {
118477411499SScott Long 				k = i + j;
118577411499SScott Long 				if (k < length)
118677411499SScott Long 					printf("%c%02x", delim, cp[k]);
118777411499SScott Long 				else
118877411499SScott Long 					printf("   ");
118977411499SScott Long 			}
119077411499SScott Long 		}
119177411499SScott Long 
119277411499SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
119377411499SScott Long 			printf("  |");
119477411499SScott Long 			for (j = 0; j < cols; j++) {
119577411499SScott Long 				k = i + j;
119677411499SScott Long 				if (k >= length)
119777411499SScott Long 					printf(" ");
119877411499SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
119977411499SScott Long 					printf("%c", cp[k]);
120077411499SScott Long 				else
120177411499SScott Long 					printf(".");
120277411499SScott Long 			}
12036ec6fb9bSScott Long 			printf("|");
120477411499SScott Long 		}
12056ec6fb9bSScott Long 		printf("\n");
120677411499SScott Long 	}
120777411499SScott Long }
12085672fac9SKenneth D. Merry #endif /* _KERNEL */
12095672fac9SKenneth D. Merry 
12105672fac9SKenneth D. Merry void
12115672fac9SKenneth D. Merry sbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
12125672fac9SKenneth D. Merry 	     int flags)
12135672fac9SKenneth D. Merry {
12145672fac9SKenneth D. Merry 	int i, j, k;
12155672fac9SKenneth D. Merry 	int cols;
12165672fac9SKenneth D. Merry 	const unsigned char *cp;
12175672fac9SKenneth D. Merry 	char delim;
12185672fac9SKenneth D. Merry 
12195672fac9SKenneth D. Merry 	if ((flags & HD_DELIM_MASK) != 0)
12205672fac9SKenneth D. Merry 		delim = (flags & HD_DELIM_MASK) >> 8;
12215672fac9SKenneth D. Merry 	else
12225672fac9SKenneth D. Merry 		delim = ' ';
12235672fac9SKenneth D. Merry 
12245672fac9SKenneth D. Merry 	if ((flags & HD_COLUMN_MASK) != 0)
12255672fac9SKenneth D. Merry 		cols = flags & HD_COLUMN_MASK;
12265672fac9SKenneth D. Merry 	else
12275672fac9SKenneth D. Merry 		cols = 16;
12285672fac9SKenneth D. Merry 
12295672fac9SKenneth D. Merry 	cp = ptr;
12305672fac9SKenneth D. Merry 	for (i = 0; i < length; i+= cols) {
12315672fac9SKenneth D. Merry 		if (hdr != NULL)
12325672fac9SKenneth D. Merry 			sbuf_printf(sb, "%s", hdr);
12335672fac9SKenneth D. Merry 
12345672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_COUNT) == 0)
12355672fac9SKenneth D. Merry 			sbuf_printf(sb, "%04x  ", i);
12365672fac9SKenneth D. Merry 
12375672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_HEX) == 0) {
12385672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12395672fac9SKenneth D. Merry 				k = i + j;
12405672fac9SKenneth D. Merry 				if (k < length)
12415672fac9SKenneth D. Merry 					sbuf_printf(sb, "%c%02x", delim, cp[k]);
12425672fac9SKenneth D. Merry 				else
1243*0a713948SAlexander Motin 					sbuf_cat(sb, "   ");
12445672fac9SKenneth D. Merry 			}
12455672fac9SKenneth D. Merry 		}
12465672fac9SKenneth D. Merry 
12475672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_CHARS) == 0) {
1248*0a713948SAlexander Motin 			sbuf_cat(sb, "  |");
12495672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12505672fac9SKenneth D. Merry 				k = i + j;
12515672fac9SKenneth D. Merry 				if (k >= length)
1252*0a713948SAlexander Motin 					sbuf_putc(sb, ' ');
12535672fac9SKenneth D. Merry 				else if (cp[k] >= ' ' && cp[k] <= '~')
1254*0a713948SAlexander Motin 					sbuf_putc(sb, cp[k]);
12555672fac9SKenneth D. Merry 				else
1256*0a713948SAlexander Motin 					sbuf_putc(sb, '.');
12575672fac9SKenneth D. Merry 			}
1258*0a713948SAlexander Motin 			sbuf_putc(sb, '|');
12595672fac9SKenneth D. Merry 		}
1260*0a713948SAlexander Motin 		sbuf_putc(sb, '\n');
12615672fac9SKenneth D. Merry 	}
12625672fac9SKenneth D. Merry }
12635672fac9SKenneth D. Merry 
1264492fe1b7SKonstantin Belousov #ifdef _KERNEL
12659837947bSKonstantin Belousov void
12669837947bSKonstantin Belousov counted_warning(unsigned *counter, const char *msg)
12679837947bSKonstantin Belousov {
12689837947bSKonstantin Belousov 	struct thread *td;
12699837947bSKonstantin Belousov 	unsigned c;
12709837947bSKonstantin Belousov 
12719837947bSKonstantin Belousov 	for (;;) {
12729837947bSKonstantin Belousov 		c = *counter;
12739837947bSKonstantin Belousov 		if (c == 0)
12749837947bSKonstantin Belousov 			break;
12759837947bSKonstantin Belousov 		if (atomic_cmpset_int(counter, c, c - 1)) {
12769837947bSKonstantin Belousov 			td = curthread;
12779837947bSKonstantin Belousov 			log(LOG_INFO, "pid %d (%s) %s%s\n",
12789837947bSKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, msg,
12799837947bSKonstantin Belousov 			    c > 1 ? "" : " - not logging anymore");
12809837947bSKonstantin Belousov 			break;
12819837947bSKonstantin Belousov 		}
12829837947bSKonstantin Belousov 	}
12839837947bSKonstantin Belousov }
1284492fe1b7SKonstantin Belousov #endif
1285388f3ce6SScott Long 
1286388f3ce6SScott Long #ifdef _KERNEL
1287388f3ce6SScott Long void
1288388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1289388f3ce6SScott Long {
1290388f3ce6SScott Long 
1291388f3ce6SScott Long 	prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1);
1292388f3ce6SScott Long }
1293388f3ce6SScott Long #else
1294388f3ce6SScott Long void
1295388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1296388f3ce6SScott Long {
1297388f3ce6SScott Long 
1298388f3ce6SScott Long 	printf("%s", sbuf_data(sb));
1299388f3ce6SScott Long }
1300388f3ce6SScott Long #endif
13017d7db529SConrad Meyer 
13027d7db529SConrad Meyer int
13037d7db529SConrad Meyer sbuf_printf_drain(void *arg, const char *data, int len)
13047d7db529SConrad Meyer {
13057d7db529SConrad Meyer 	size_t *retvalptr;
13067d7db529SConrad Meyer 	int r;
13077d7db529SConrad Meyer #ifdef _KERNEL
13087d7db529SConrad Meyer 	char *dataptr;
13097d7db529SConrad Meyer 	char oldchr;
13107d7db529SConrad Meyer 
13117d7db529SConrad Meyer 	/*
13127d7db529SConrad Meyer 	 * This is allowed as an extra byte is always resvered for
13137d7db529SConrad Meyer 	 * terminating NUL byte.  Save and restore the byte because
13147d7db529SConrad Meyer 	 * we might be flushing a record, and there may be valid
13157d7db529SConrad Meyer 	 * data after the buffer.
13167d7db529SConrad Meyer 	 */
13177d7db529SConrad Meyer 	oldchr = data[len];
13187d7db529SConrad Meyer 	dataptr = __DECONST(char *, data);
13197d7db529SConrad Meyer 	dataptr[len] = '\0';
13207d7db529SConrad Meyer 
13217d7db529SConrad Meyer 	prf_putbuf(dataptr, TOLOG | TOCONS, -1);
13227d7db529SConrad Meyer 	r = len;
13237d7db529SConrad Meyer 
13247d7db529SConrad Meyer 	dataptr[len] = oldchr;
13257d7db529SConrad Meyer 
13267d7db529SConrad Meyer #else /* !_KERNEL */
13277d7db529SConrad Meyer 
13287d7db529SConrad Meyer 	r = printf("%.*s", len, data);
13297d7db529SConrad Meyer 	if (r < 0)
13307d7db529SConrad Meyer 		return (-errno);
13317d7db529SConrad Meyer 
13327d7db529SConrad Meyer #endif
13337d7db529SConrad Meyer 
13347d7db529SConrad Meyer 	retvalptr = arg;
13357d7db529SConrad Meyer 	if (retvalptr != NULL)
13367d7db529SConrad Meyer 		*retvalptr += r;
13377d7db529SConrad Meyer 
13387d7db529SConrad Meyer 	return (r);
13397d7db529SConrad Meyer }
1340