xref: /freebsd/sys/kern/subr_prf.c (revision a264594d4ff19fd13f7c39a56c8d131296db480d)
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>
40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
41677b542eSDavid E. O'Brien 
425672fac9SKenneth D. Merry #ifdef _KERNEL
433ae59505SPoul-Henning Kamp #include "opt_ddb.h"
44e0b65125SJohn Birrell #include "opt_printf.h"
455672fac9SKenneth D. Merry #endif  /* _KERNEL */
463ae59505SPoul-Henning Kamp 
47df8bae1dSRodney W. Grimes #include <sys/param.h>
485672fac9SKenneth D. Merry #ifdef _KERNEL
49df8bae1dSRodney W. Grimes #include <sys/systm.h>
50f591779bSSeigo Tanimura #include <sys/lock.h>
5182ebaee7SMarcel Moolenaar #include <sys/kdb.h>
52f591779bSSeigo Tanimura #include <sys/mutex.h>
53f591779bSSeigo Tanimura #include <sys/sx.h>
54e796e00dSPoul-Henning Kamp #include <sys/kernel.h>
55df8bae1dSRodney W. Grimes #include <sys/msgbuf.h>
56a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
57acd3428bSRobert Watson #include <sys/priv.h>
58df8bae1dSRodney W. Grimes #include <sys/proc.h>
592bb95458SMaxime Henrion #include <sys/stddef.h>
6058a24f79SPoul-Henning Kamp #include <sys/sysctl.h>
61df8bae1dSRodney W. Grimes #include <sys/tty.h>
62df8bae1dSRodney W. Grimes #include <sys/syslog.h>
63ce9edcf5SPoul-Henning Kamp #include <sys/cons.h>
64e2a09b26SPoul-Henning Kamp #include <sys/uio.h>
657d7db529SConrad Meyer #else /* !_KERNEL */
667d7db529SConrad Meyer #include <errno.h>
675672fac9SKenneth D. Merry #endif
680d84d9ebSJung-uk Kim #include <sys/ctype.h>
695672fac9SKenneth D. Merry #include <sys/sbuf.h>
70df8bae1dSRodney W. Grimes 
713ae59505SPoul-Henning Kamp #ifdef DDB
723ae59505SPoul-Henning Kamp #include <ddb/ddb.h>
733ae59505SPoul-Henning Kamp #endif
743ae59505SPoul-Henning Kamp 
75df8bae1dSRodney W. Grimes /*
76df8bae1dSRodney W. Grimes  * Note that stdarg.h and the ANSI style va_start macro is used for both
77df8bae1dSRodney W. Grimes  * ANSI and traditional C compilers.
78df8bae1dSRodney W. Grimes  */
7907f862a7SMarcel Moolenaar #ifdef _KERNEL
80df8bae1dSRodney W. Grimes #include <machine/stdarg.h>
8107f862a7SMarcel Moolenaar #else
8207f862a7SMarcel Moolenaar #include <stdarg.h>
8338e41e66SScott Long #endif
8438e41e66SScott Long 
8538e41e66SScott Long /*
8638e41e66SScott Long  * This is needed for sbuf_putbuf() when compiled into userland.  Due to the
8738e41e66SScott Long  * shared nature of this file, it's the only place to put it.
8838e41e66SScott Long  */
8938e41e66SScott Long #ifndef _KERNEL
90c4e92994SJung-uk Kim #include <stdio.h>
9107f862a7SMarcel Moolenaar #endif
92df8bae1dSRodney W. Grimes 
935672fac9SKenneth D. Merry #ifdef _KERNEL
945672fac9SKenneth D. Merry 
95df8bae1dSRodney W. Grimes #define TOCONS	0x01
96df8bae1dSRodney W. Grimes #define TOTTY	0x02
97df8bae1dSRodney W. Grimes #define TOLOG	0x04
98df8bae1dSRodney W. Grimes 
9982941964SPeter Wemm /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
1003b1f7e7dSDag-Erling Smørgrav #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
101df8bae1dSRodney W. Grimes 
1028245f3f5SArchie Cobbs struct putchar_arg {
1038245f3f5SArchie Cobbs 	int	flags;
104e2a09b26SPoul-Henning Kamp 	int	pri;
1058245f3f5SArchie Cobbs 	struct	tty *tty;
1063d068827SJohn Birrell 	char	*p_bufr;
1073d068827SJohn Birrell 	size_t	n_bufr;
1083d068827SJohn Birrell 	char	*p_next;
1093d068827SJohn Birrell 	size_t	remain;
1108245f3f5SArchie Cobbs };
1118245f3f5SArchie Cobbs 
1128245f3f5SArchie Cobbs struct snprintf_arg {
1138245f3f5SArchie Cobbs 	char	*str;
1148245f3f5SArchie Cobbs 	size_t	remain;
1158245f3f5SArchie Cobbs };
1168245f3f5SArchie Cobbs 
117e2a09b26SPoul-Henning Kamp extern	int log_open;
118e2a09b26SPoul-Henning Kamp 
119e2a09b26SPoul-Henning Kamp static void  msglogchar(int c, int pri);
120d42a4eb5SKenneth D. Merry static void  msglogstr(char *str, int pri, int filter_cr);
121*a264594dSAlexander Motin static void  prf_putbuf(char *bufr, int flags, int pri);
1224d77a549SAlfred Perlstein static void  putchar(int ch, void *arg);
1230d84d9ebSJung-uk Kim static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
1244d77a549SAlfred Perlstein static void  snprintf_func(int ch, void *arg);
125df8bae1dSRodney W. Grimes 
12621aa6e83SKyle Evans static bool msgbufmapped;		/* Set when safe to use msgbuf */
127e2a09b26SPoul-Henning Kamp int msgbuftrigger;
128fb3cc1c3SBruce Evans struct msgbuf *msgbufp;
129df8bae1dSRodney W. Grimes 
1302a4650ccSKyle Evans #ifndef BOOT_TAG_SZ
1312a4650ccSKyle Evans #define	BOOT_TAG_SZ	32
1322a4650ccSKyle Evans #endif
1332a4650ccSKyle Evans #ifndef BOOT_TAG
1342a4650ccSKyle Evans /* Tag used to mark the start of a boot in dmesg */
1352a4650ccSKyle Evans #define	BOOT_TAG	"---<<BOOT>>---"
1362a4650ccSKyle Evans #endif
1372a4650ccSKyle Evans 
1382a4650ccSKyle Evans static char current_boot_tag[BOOT_TAG_SZ + 1] = BOOT_TAG;
1392a4650ccSKyle Evans SYSCTL_STRING(_kern, OID_AUTO, boot_tag, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
1402a4650ccSKyle Evans     current_boot_tag, 0, "Tag added to dmesg at start of boot");
1412a4650ccSKyle Evans 
142dbe620d3SDavid Malone static int log_console_output = 1;
143af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
144af3b2549SHans Petter Selasky     &log_console_output, 0, "Duplicate console output to the syslog");
1458e1b7974SBrian Feldman 
146d42a4eb5SKenneth D. Merry /*
147d42a4eb5SKenneth D. Merry  * See the comment in log_console() below for more explanation of this.
148d42a4eb5SKenneth D. Merry  */
149af3b2549SHans Petter Selasky static int log_console_add_linefeed;
150af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
151af3b2549SHans Petter Selasky     &log_console_add_linefeed, 0, "log_console() adds extra newlines");
152d42a4eb5SKenneth D. Merry 
153af3b2549SHans Petter Selasky static int always_console_output;
154af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
155af3b2549SHans Petter Selasky     &always_console_output, 0, "Always output to console despite TIOCCONS");
156dbe620d3SDavid Malone 
157df8bae1dSRodney W. Grimes /*
158df8bae1dSRodney W. Grimes  * Warn that a system table is full.
159df8bae1dSRodney W. Grimes  */
160df8bae1dSRodney W. Grimes void
161e2a09b26SPoul-Henning Kamp tablefull(const char *tab)
162df8bae1dSRodney W. Grimes {
163df8bae1dSRodney W. Grimes 
164df8bae1dSRodney W. Grimes 	log(LOG_ERR, "%s: table is full\n", tab);
165df8bae1dSRodney W. Grimes }
166df8bae1dSRodney W. Grimes 
167df8bae1dSRodney W. Grimes /*
168df8bae1dSRodney W. Grimes  * Uprintf prints to the controlling terminal for the current process.
169df8bae1dSRodney W. Grimes  */
170f1550d9dSDoug Rabson int
171df8bae1dSRodney W. Grimes uprintf(const char *fmt, ...)
172df8bae1dSRodney W. Grimes {
173df8bae1dSRodney W. Grimes 	va_list ap;
174791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
175ff7b7d90SEd Schouten 	struct proc *p;
176ff7b7d90SEd Schouten 	struct thread *td;
177f591779bSSeigo Tanimura 	int retval;
178df8bae1dSRodney W. Grimes 
179ff7b7d90SEd Schouten 	td = curthread;
180ff7b7d90SEd Schouten 	if (TD_IS_IDLETHREAD(td))
181f591779bSSeigo Tanimura 		return (0);
182f591779bSSeigo Tanimura 
1837e99c034SAlex Richardson 	if (td->td_proc == initproc) {
1847e99c034SAlex Richardson 		/* Produce output when we fail to load /sbin/init: */
1857e99c034SAlex Richardson 		va_start(ap, fmt);
1867e99c034SAlex Richardson 		retval = vprintf(fmt, ap);
1877e99c034SAlex Richardson 		va_end(ap);
1887e99c034SAlex Richardson 		return (retval);
1897e99c034SAlex Richardson 	}
1907e99c034SAlex Richardson 
191bc093719SEd Schouten 	sx_slock(&proctree_lock);
192ff7b7d90SEd Schouten 	p = td->td_proc;
193f591779bSSeigo Tanimura 	PROC_LOCK(p);
194f591779bSSeigo Tanimura 	if ((p->p_flag & P_CONTROLT) == 0) {
195f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
1968740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
1978740a711SKonstantin Belousov 		return (0);
198f591779bSSeigo Tanimura 	}
199f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
200791d77e0SPoul-Henning Kamp 	pca.tty = p->p_session->s_ttyp;
201f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
202f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
203329c75a7SRobert Watson 	if (pca.tty == NULL) {
2048740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
2058740a711SKonstantin Belousov 		return (0);
206329c75a7SRobert Watson 	}
207791d77e0SPoul-Henning Kamp 	pca.flags = TOTTY;
2085e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
209f591779bSSeigo Tanimura 	va_start(ap, fmt);
210bc093719SEd Schouten 	tty_lock(pca.tty);
2118740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
212f1550d9dSDoug Rabson 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
213bc093719SEd Schouten 	tty_unlock(pca.tty);
214df8bae1dSRodney W. Grimes 	va_end(ap);
21558a24f79SPoul-Henning Kamp 	return (retval);
216df8bae1dSRodney W. Grimes }
217df8bae1dSRodney W. Grimes 
218df8bae1dSRodney W. Grimes /*
21934c916c6SNavdeep Parhar  * tprintf and vtprintf print on the controlling terminal associated with the
22034c916c6SNavdeep Parhar  * given session, possibly to the log as well.
221df8bae1dSRodney W. Grimes  */
222a52585d7SPoul-Henning Kamp void
223a52585d7SPoul-Henning Kamp tprintf(struct proc *p, int pri, const char *fmt, ...)
224df8bae1dSRodney W. Grimes {
22534c916c6SNavdeep Parhar 	va_list ap;
22634c916c6SNavdeep Parhar 
22734c916c6SNavdeep Parhar 	va_start(ap, fmt);
22834c916c6SNavdeep Parhar 	vtprintf(p, pri, fmt, ap);
22934c916c6SNavdeep Parhar 	va_end(ap);
23034c916c6SNavdeep Parhar }
23134c916c6SNavdeep Parhar 
23234c916c6SNavdeep Parhar void
23334c916c6SNavdeep Parhar vtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
23434c916c6SNavdeep Parhar {
235df8bae1dSRodney W. Grimes 	struct tty *tp = NULL;
236b5a2bad1SJohn Baldwin 	int flags = 0;
237791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
238b5a2bad1SJohn Baldwin 	struct session *sess = NULL;
239df8bae1dSRodney W. Grimes 
240bc093719SEd Schouten 	sx_slock(&proctree_lock);
241e2a09b26SPoul-Henning Kamp 	if (pri != -1)
242a52585d7SPoul-Henning Kamp 		flags |= TOLOG;
243f591779bSSeigo Tanimura 	if (p != NULL) {
244f591779bSSeigo Tanimura 		PROC_LOCK(p);
245f591779bSSeigo Tanimura 		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
246b5a2bad1SJohn Baldwin 			sess = p->p_session;
247bc093719SEd Schouten 			sess_hold(sess);
248f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
249b5a2bad1SJohn Baldwin 			tp = sess->s_ttyp;
250bc093719SEd Schouten 			if (tp != NULL && tty_checkoutq(tp))
251f591779bSSeigo Tanimura 				flags |= TOTTY;
252f591779bSSeigo Tanimura 			else
253f591779bSSeigo Tanimura 				tp = NULL;
254f591779bSSeigo Tanimura 		} else
255f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
256a52585d7SPoul-Henning Kamp 	}
257e2a09b26SPoul-Henning Kamp 	pca.pri = pri;
258791d77e0SPoul-Henning Kamp 	pca.tty = tp;
259791d77e0SPoul-Henning Kamp 	pca.flags = flags;
2605e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
261bc093719SEd Schouten 	if (pca.tty != NULL)
262bc093719SEd Schouten 		tty_lock(pca.tty);
2638740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
26474f1af01SPoul-Henning Kamp 	kvprintf(fmt, putchar, &pca, 10, ap);
265bc093719SEd Schouten 	if (pca.tty != NULL)
266bc093719SEd Schouten 		tty_unlock(pca.tty);
267572b4402SPoul-Henning Kamp 	if (sess != NULL)
268bc093719SEd Schouten 		sess_release(sess);
269e2a09b26SPoul-Henning Kamp 	msgbuftrigger = 1;
270df8bae1dSRodney W. Grimes }
271df8bae1dSRodney W. Grimes 
272ae8959ddSBryan Drewery static int
273ae8959ddSBryan Drewery _vprintf(int level, int flags, const char *fmt, va_list ap)
274df8bae1dSRodney W. Grimes {
275791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
276ae8959ddSBryan Drewery 	int retval;
277d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
278d42a4eb5SKenneth D. Merry 	char bufr[PRINTF_BUFR_SIZE];
279d42a4eb5SKenneth D. Merry #endif
280e2a09b26SPoul-Henning Kamp 
281d5d7606cSColin Percival 	TSENTER();
282791d77e0SPoul-Henning Kamp 	pca.tty = NULL;
283e2a09b26SPoul-Henning Kamp 	pca.pri = level;
284ae8959ddSBryan Drewery 	pca.flags = flags;
285d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
286d42a4eb5SKenneth D. Merry 	pca.p_bufr = bufr;
287d42a4eb5SKenneth D. Merry 	pca.p_next = pca.p_bufr;
288d42a4eb5SKenneth D. Merry 	pca.n_bufr = sizeof(bufr);
289d42a4eb5SKenneth D. Merry 	pca.remain = sizeof(bufr);
290d42a4eb5SKenneth D. Merry 	*pca.p_next = '\0';
291d42a4eb5SKenneth D. Merry #else
292ae8959ddSBryan Drewery 	/* Don't buffer console output. */
2933d068827SJohn Birrell 	pca.p_bufr = NULL;
294d42a4eb5SKenneth D. Merry #endif
295e2a09b26SPoul-Henning Kamp 
296ae8959ddSBryan Drewery 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
297e2a09b26SPoul-Henning Kamp 
298d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
299d42a4eb5SKenneth D. Merry 	/* Write any buffered console/log output: */
300*a264594dSAlexander Motin 	if (*pca.p_bufr != '\0')
301*a264594dSAlexander Motin 		prf_putbuf(pca.p_bufr, flags, level);
302d42a4eb5SKenneth D. Merry #endif
303ae8959ddSBryan Drewery 
304d5d7606cSColin Percival 	TSEXIT();
305ae8959ddSBryan Drewery 	return (retval);
306ae8959ddSBryan Drewery }
307ae8959ddSBryan Drewery 
308ae8959ddSBryan Drewery /*
309ae8959ddSBryan Drewery  * Log writes to the log buffer, and guarantees not to sleep (so can be
310ae8959ddSBryan Drewery  * called by interrupt routines).  If there is no process reading the
311ae8959ddSBryan Drewery  * log yet, it writes to the console also.
312ae8959ddSBryan Drewery  */
313ae8959ddSBryan Drewery void
314ae8959ddSBryan Drewery log(int level, const char *fmt, ...)
315ae8959ddSBryan Drewery {
316ae8959ddSBryan Drewery 	va_list ap;
317ae8959ddSBryan Drewery 
318ae8959ddSBryan Drewery 	va_start(ap, fmt);
31907713ddeSMark Johnston 	vlog(level, fmt, ap);
320ae8959ddSBryan Drewery 	va_end(ap);
32107713ddeSMark Johnston }
322ae8959ddSBryan Drewery 
32307713ddeSMark Johnston void
32407713ddeSMark Johnston vlog(int level, const char *fmt, va_list ap)
32507713ddeSMark Johnston {
32607713ddeSMark Johnston 
32707713ddeSMark Johnston 	(void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
328b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
329df8bae1dSRodney W. Grimes }
330df8bae1dSRodney W. Grimes 
331e2a09b26SPoul-Henning Kamp #define CONSCHUNK 128
332e2a09b26SPoul-Henning Kamp 
333e2a09b26SPoul-Henning Kamp void
334e2a09b26SPoul-Henning Kamp log_console(struct uio *uio)
335df8bae1dSRodney W. Grimes {
336d42a4eb5SKenneth D. Merry 	int c, error, nl;
337e2a09b26SPoul-Henning Kamp 	char *consbuffer;
338e2a09b26SPoul-Henning Kamp 	int pri;
339df8bae1dSRodney W. Grimes 
340dbe620d3SDavid Malone 	if (!log_console_output)
341dbe620d3SDavid Malone 		return;
342dbe620d3SDavid Malone 
343e2a09b26SPoul-Henning Kamp 	pri = LOG_INFO | LOG_CONSOLE;
344552afd9cSPoul-Henning Kamp 	uio = cloneuio(uio);
345552afd9cSPoul-Henning Kamp 	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
346e2a09b26SPoul-Henning Kamp 
3473a4d0c86SEd Schouten 	nl = 0;
348e2a09b26SPoul-Henning Kamp 	while (uio->uio_resid > 0) {
349d42a4eb5SKenneth D. Merry 		c = imin(uio->uio_resid, CONSCHUNK - 1);
350e2a09b26SPoul-Henning Kamp 		error = uiomove(consbuffer, c, uio);
351e2a09b26SPoul-Henning Kamp 		if (error != 0)
3522f9752e9SPoul-Henning Kamp 			break;
353d42a4eb5SKenneth D. Merry 		/* Make sure we're NUL-terminated */
354d42a4eb5SKenneth D. Merry 		consbuffer[c] = '\0';
355d42a4eb5SKenneth D. Merry 		if (consbuffer[c - 1] == '\n')
3563a4d0c86SEd Schouten 			nl = 1;
3573a4d0c86SEd Schouten 		else
3583a4d0c86SEd Schouten 			nl = 0;
359d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
360e2a09b26SPoul-Henning Kamp 	}
361d42a4eb5SKenneth D. Merry 	/*
362d42a4eb5SKenneth D. Merry 	 * The previous behavior in log_console() is preserved when
363d42a4eb5SKenneth D. Merry 	 * log_console_add_linefeed is non-zero.  For that behavior, if an
364d42a4eb5SKenneth D. Merry 	 * individual console write came in that was not terminated with a
365d42a4eb5SKenneth D. Merry 	 * line feed, it would add a line feed.
366d42a4eb5SKenneth D. Merry 	 *
367d42a4eb5SKenneth D. Merry 	 * This results in different data in the message buffer than
368d42a4eb5SKenneth D. Merry 	 * appears on the system console (which doesn't add extra line feed
369d42a4eb5SKenneth D. Merry 	 * characters).
370d42a4eb5SKenneth D. Merry 	 *
371d42a4eb5SKenneth D. Merry 	 * A number of programs and rc scripts write a line feed, or a period
372d42a4eb5SKenneth D. Merry 	 * and a line feed when they have completed their operation.  On
373d42a4eb5SKenneth D. Merry 	 * the console, this looks seamless, but when displayed with
374d42a4eb5SKenneth D. Merry 	 * 'dmesg -a', you wind up with output that looks like this:
375d42a4eb5SKenneth D. Merry 	 *
376d42a4eb5SKenneth D. Merry 	 * Updating motd:
377d42a4eb5SKenneth D. Merry 	 * .
378d42a4eb5SKenneth D. Merry 	 *
379d42a4eb5SKenneth D. Merry 	 * On the console, it looks like this:
380d42a4eb5SKenneth D. Merry 	 * Updating motd:.
381d42a4eb5SKenneth D. Merry 	 *
382d42a4eb5SKenneth D. Merry 	 * We could add logic to detect that situation, or just not insert
383d42a4eb5SKenneth D. Merry 	 * the extra newlines.  Set the kern.log_console_add_linefeed
384d42a4eb5SKenneth D. Merry 	 * sysctl/tunable variable to get the old behavior.
385d42a4eb5SKenneth D. Merry 	 */
386d42a4eb5SKenneth D. Merry 	if (!nl && log_console_add_linefeed) {
387d42a4eb5SKenneth D. Merry 		consbuffer[0] = '\n';
388d42a4eb5SKenneth D. Merry 		consbuffer[1] = '\0';
389d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
3903a4d0c86SEd Schouten 	}
391b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
392552afd9cSPoul-Henning Kamp 	free(uio, M_IOV);
393552afd9cSPoul-Henning Kamp 	free(consbuffer, M_TEMP);
394df8bae1dSRodney W. Grimes }
395df8bae1dSRodney W. Grimes 
3966ddbf1e2SGary Palmer int
397df8bae1dSRodney W. Grimes printf(const char *fmt, ...)
398df8bae1dSRodney W. Grimes {
399df8bae1dSRodney W. Grimes 	va_list ap;
40065ed8cbdSJustin T. Gibbs 	int retval;
4013d068827SJohn Birrell 
402df8bae1dSRodney W. Grimes 	va_start(ap, fmt);
40391c3cbfeSEd Schouten 	retval = vprintf(fmt, ap);
404df8bae1dSRodney W. Grimes 	va_end(ap);
4053d068827SJohn Birrell 
40658a24f79SPoul-Henning Kamp 	return (retval);
407df8bae1dSRodney W. Grimes }
408df8bae1dSRodney W. Grimes 
409f1550d9dSDoug Rabson int
410791d77e0SPoul-Henning Kamp vprintf(const char *fmt, va_list ap)
411791d77e0SPoul-Henning Kamp {
412f1550d9dSDoug Rabson 	int retval;
4133d068827SJohn Birrell 
414ae8959ddSBryan Drewery 	retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
4153d068827SJohn Birrell 
416879e0604SMateusz Guzik 	if (!KERNEL_PANICKED())
417b80e3b41SPoul-Henning Kamp 		msgbuftrigger = 1;
4183d068827SJohn Birrell 
41958a24f79SPoul-Henning Kamp 	return (retval);
420791d77e0SPoul-Henning Kamp }
421791d77e0SPoul-Henning Kamp 
4223d068827SJohn Birrell static void
423*a264594dSAlexander Motin prf_putchar(int c, int flags, int pri)
424*a264594dSAlexander Motin {
425*a264594dSAlexander Motin 
426*a264594dSAlexander Motin 	if (flags & TOLOG)
427*a264594dSAlexander Motin 		msglogchar(c, pri);
428*a264594dSAlexander Motin 
429*a264594dSAlexander Motin 	if (flags & TOCONS) {
430*a264594dSAlexander Motin 		if ((!KERNEL_PANICKED()) && (constty != NULL))
431*a264594dSAlexander Motin 			msgbuf_addchar(&consmsgbuf, c);
432*a264594dSAlexander Motin 
433*a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
434*a264594dSAlexander Motin 			cnputc(c);
435*a264594dSAlexander Motin 	}
436*a264594dSAlexander Motin }
437*a264594dSAlexander Motin 
438*a264594dSAlexander Motin static void
439388f3ce6SScott Long prf_putbuf(char *bufr, int flags, int pri)
440388f3ce6SScott Long {
441388f3ce6SScott Long 
442388f3ce6SScott Long 	if (flags & TOLOG)
443388f3ce6SScott Long 		msglogstr(bufr, pri, /*filter_cr*/1);
444388f3ce6SScott Long 
445388f3ce6SScott Long 	if (flags & TOCONS) {
446879e0604SMateusz Guzik 		if ((!KERNEL_PANICKED()) && (constty != NULL))
447388f3ce6SScott Long 			msgbuf_addstr(&consmsgbuf, -1,
448388f3ce6SScott Long 			    bufr, /*filter_cr*/ 0);
449388f3ce6SScott Long 
450*a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
451388f3ce6SScott Long 			cnputs(bufr);
452388f3ce6SScott Long 	}
453388f3ce6SScott Long }
454388f3ce6SScott Long 
455388f3ce6SScott Long static void
456d42a4eb5SKenneth D. Merry putbuf(int c, struct putchar_arg *ap)
4573d068827SJohn Birrell {
4583d068827SJohn Birrell 	/* Check if no console output buffer was provided. */
459d42a4eb5SKenneth D. Merry 	if (ap->p_bufr == NULL) {
460*a264594dSAlexander Motin 		prf_putchar(c, ap->flags, ap->pri);
461d42a4eb5SKenneth D. Merry 	} else {
4623d068827SJohn Birrell 		/* Buffer the character: */
4633d068827SJohn Birrell 		*ap->p_next++ = c;
4643d068827SJohn Birrell 		ap->remain--;
4653d068827SJohn Birrell 
4663d068827SJohn Birrell 		/* Always leave the buffer zero terminated. */
4673d068827SJohn Birrell 		*ap->p_next = '\0';
4683d068827SJohn Birrell 
4693d068827SJohn Birrell 		/* Check if the buffer needs to be flushed. */
470d42a4eb5SKenneth D. Merry 		if (ap->remain == 2 || c == '\n') {
471388f3ce6SScott Long 			prf_putbuf(ap->p_bufr, ap->flags, ap->pri);
472d42a4eb5SKenneth D. Merry 
4733d068827SJohn Birrell 			ap->p_next = ap->p_bufr;
4743d068827SJohn Birrell 			ap->remain = ap->n_bufr;
4753d068827SJohn Birrell 			*ap->p_next = '\0';
4763d068827SJohn Birrell 		}
477d42a4eb5SKenneth D. Merry 
478d42a4eb5SKenneth D. Merry 		/*
479d42a4eb5SKenneth D. Merry 		 * Since we fill the buffer up one character at a time,
480d42a4eb5SKenneth D. Merry 		 * this should not happen.  We should always catch it when
481d42a4eb5SKenneth D. Merry 		 * ap->remain == 2 (if not sooner due to a newline), flush
482d42a4eb5SKenneth D. Merry 		 * the buffer and move on.  One way this could happen is
483d42a4eb5SKenneth D. Merry 		 * if someone sets PRINTF_BUFR_SIZE to 1 or something
484d42a4eb5SKenneth D. Merry 		 * similarly silly.
485d42a4eb5SKenneth D. Merry 		 */
486d42a4eb5SKenneth D. Merry 		KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
487d42a4eb5SKenneth D. Merry 		    ap->remain));
4883d068827SJohn Birrell 	}
4893d068827SJohn Birrell }
4903d068827SJohn Birrell 
491791d77e0SPoul-Henning Kamp /*
492791d77e0SPoul-Henning Kamp  * Print a character on console or users terminal.  If destination is
493e796e00dSPoul-Henning Kamp  * the console then the last bunch of characters are saved in msgbuf for
494791d77e0SPoul-Henning Kamp  * inspection later.
495791d77e0SPoul-Henning Kamp  */
496791d77e0SPoul-Henning Kamp static void
497791d77e0SPoul-Henning Kamp putchar(int c, void *arg)
498791d77e0SPoul-Henning Kamp {
499791d77e0SPoul-Henning Kamp 	struct putchar_arg *ap = (struct putchar_arg*) arg;
500791d77e0SPoul-Henning Kamp 	struct tty *tp = ap->tty;
5013d068827SJohn Birrell 	int flags = ap->flags;
502d29bf12fSIan Dowse 
503adef9265SIan Dowse 	/* Don't use the tty code after a panic or while in ddb. */
5043d068827SJohn Birrell 	if (kdb_active) {
505d29bf12fSIan Dowse 		if (c != '\0')
506d29bf12fSIan Dowse 			cnputc(c);
50780f1c58bSMarcel Moolenaar 		return;
50880f1c58bSMarcel Moolenaar 	}
50980f1c58bSMarcel Moolenaar 
510879e0604SMateusz Guzik 	if ((flags & TOTTY) && tp != NULL && !KERNEL_PANICKED())
511bc093719SEd Schouten 		tty_putchar(tp, c);
512d42a4eb5SKenneth D. Merry 
51380f1c58bSMarcel Moolenaar 	if ((flags & (TOCONS | TOLOG)) && c != '\0')
514d42a4eb5SKenneth D. Merry 		putbuf(c, ap);
515791d77e0SPoul-Henning Kamp }
516791d77e0SPoul-Henning Kamp 
517791d77e0SPoul-Henning Kamp /*
518791d77e0SPoul-Henning Kamp  * Scaled down version of sprintf(3).
519791d77e0SPoul-Henning Kamp  */
520791d77e0SPoul-Henning Kamp int
521791d77e0SPoul-Henning Kamp sprintf(char *buf, const char *cfmt, ...)
522791d77e0SPoul-Henning Kamp {
523791d77e0SPoul-Henning Kamp 	int retval;
524791d77e0SPoul-Henning Kamp 	va_list ap;
525791d77e0SPoul-Henning Kamp 
526791d77e0SPoul-Henning Kamp 	va_start(ap, cfmt);
527791d77e0SPoul-Henning Kamp 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
528fe96d47dSPoul-Henning Kamp 	buf[retval] = '\0';
529791d77e0SPoul-Henning Kamp 	va_end(ap);
53058a24f79SPoul-Henning Kamp 	return (retval);
531791d77e0SPoul-Henning Kamp }
532791d77e0SPoul-Henning Kamp 
533791d77e0SPoul-Henning Kamp /*
53499237364SAndrey A. Chernov  * Scaled down version of vsprintf(3).
53599237364SAndrey A. Chernov  */
53699237364SAndrey A. Chernov int
53799237364SAndrey A. Chernov vsprintf(char *buf, const char *cfmt, va_list ap)
53899237364SAndrey A. Chernov {
53999237364SAndrey A. Chernov 	int retval;
54099237364SAndrey A. Chernov 
54199237364SAndrey A. Chernov 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
54299237364SAndrey A. Chernov 	buf[retval] = '\0';
54358a24f79SPoul-Henning Kamp 	return (retval);
54499237364SAndrey A. Chernov }
54599237364SAndrey A. Chernov 
54699237364SAndrey A. Chernov /*
5478245f3f5SArchie Cobbs  * Scaled down version of snprintf(3).
5488245f3f5SArchie Cobbs  */
5498245f3f5SArchie Cobbs int
5508245f3f5SArchie Cobbs snprintf(char *str, size_t size, const char *format, ...)
5518245f3f5SArchie Cobbs {
5528245f3f5SArchie Cobbs 	int retval;
5538245f3f5SArchie Cobbs 	va_list ap;
5548245f3f5SArchie Cobbs 
5558245f3f5SArchie Cobbs 	va_start(ap, format);
5568245f3f5SArchie Cobbs 	retval = vsnprintf(str, size, format, ap);
5578245f3f5SArchie Cobbs 	va_end(ap);
5588245f3f5SArchie Cobbs 	return(retval);
5598245f3f5SArchie Cobbs }
5608245f3f5SArchie Cobbs 
5618245f3f5SArchie Cobbs /*
5628245f3f5SArchie Cobbs  * Scaled down version of vsnprintf(3).
5638245f3f5SArchie Cobbs  */
5648245f3f5SArchie Cobbs int
5658245f3f5SArchie Cobbs vsnprintf(char *str, size_t size, const char *format, va_list ap)
5668245f3f5SArchie Cobbs {
5678245f3f5SArchie Cobbs 	struct snprintf_arg info;
5688245f3f5SArchie Cobbs 	int retval;
5698245f3f5SArchie Cobbs 
5708245f3f5SArchie Cobbs 	info.str = str;
5718245f3f5SArchie Cobbs 	info.remain = size;
5728245f3f5SArchie Cobbs 	retval = kvprintf(format, snprintf_func, &info, 10, ap);
5738245f3f5SArchie Cobbs 	if (info.remain >= 1)
5748245f3f5SArchie Cobbs 		*info.str++ = '\0';
57558a24f79SPoul-Henning Kamp 	return (retval);
5768245f3f5SArchie Cobbs }
5778245f3f5SArchie Cobbs 
5788751a8c7SPoul-Henning Kamp /*
5798751a8c7SPoul-Henning Kamp  * Kernel version which takes radix argument vsnprintf(3).
5808751a8c7SPoul-Henning Kamp  */
5818751a8c7SPoul-Henning Kamp int
5828751a8c7SPoul-Henning Kamp vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
5838751a8c7SPoul-Henning Kamp {
5848751a8c7SPoul-Henning Kamp 	struct snprintf_arg info;
5858751a8c7SPoul-Henning Kamp 	int retval;
5868751a8c7SPoul-Henning Kamp 
5878751a8c7SPoul-Henning Kamp 	info.str = str;
5888751a8c7SPoul-Henning Kamp 	info.remain = size;
5898751a8c7SPoul-Henning Kamp 	retval = kvprintf(format, snprintf_func, &info, radix, ap);
5908751a8c7SPoul-Henning Kamp 	if (info.remain >= 1)
5918751a8c7SPoul-Henning Kamp 		*info.str++ = '\0';
5928751a8c7SPoul-Henning Kamp 	return (retval);
5938751a8c7SPoul-Henning Kamp }
5948751a8c7SPoul-Henning Kamp 
5958245f3f5SArchie Cobbs static void
5968245f3f5SArchie Cobbs snprintf_func(int ch, void *arg)
5978245f3f5SArchie Cobbs {
5988245f3f5SArchie Cobbs 	struct snprintf_arg *const info = arg;
5998245f3f5SArchie Cobbs 
6008245f3f5SArchie Cobbs 	if (info->remain >= 2) {
6018245f3f5SArchie Cobbs 		*info->str++ = ch;
6028245f3f5SArchie Cobbs 		info->remain--;
6038245f3f5SArchie Cobbs 	}
6048245f3f5SArchie Cobbs }
6058245f3f5SArchie Cobbs 
6068245f3f5SArchie Cobbs /*
60782941964SPeter Wemm  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
60805292ba2SArchie Cobbs  * order; return an optional length and a pointer to the last character
60905292ba2SArchie Cobbs  * written in the buffer (i.e., the first character of the string).
61005292ba2SArchie Cobbs  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
611791d77e0SPoul-Henning Kamp  */
612791d77e0SPoul-Henning Kamp static char *
6130d84d9ebSJung-uk Kim ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
61405292ba2SArchie Cobbs {
6150d84d9ebSJung-uk Kim 	char *p, c;
616791d77e0SPoul-Henning Kamp 
61705292ba2SArchie Cobbs 	p = nbuf;
618ad4f8dbdSArchie Cobbs 	*p = '\0';
619791d77e0SPoul-Henning Kamp 	do {
6200d84d9ebSJung-uk Kim 		c = hex2ascii(num % base);
6210d84d9ebSJung-uk Kim 		*++p = upper ? toupper(c) : c;
6223b1f7e7dSDag-Erling Smørgrav 	} while (num /= base);
6237d921a01SPeter Wemm 	if (lenp)
6247d921a01SPeter Wemm 		*lenp = p - nbuf;
6257d921a01SPeter Wemm 	return (p);
6267d921a01SPeter Wemm }
627791d77e0SPoul-Henning Kamp 
628df8bae1dSRodney W. Grimes /*
629df8bae1dSRodney W. Grimes  * Scaled down version of printf(3).
630df8bae1dSRodney W. Grimes  *
631df8bae1dSRodney W. Grimes  * Two additional formats:
632df8bae1dSRodney W. Grimes  *
633df8bae1dSRodney W. Grimes  * The format %b is supported to decode error registers.
634df8bae1dSRodney W. Grimes  * Its usage is:
635df8bae1dSRodney W. Grimes  *
636df8bae1dSRodney W. Grimes  *	printf("reg=%b\n", regval, "<base><arg>*");
637df8bae1dSRodney W. Grimes  *
638df8bae1dSRodney W. Grimes  * where <base> is the output base expressed as a control character, e.g.
639df8bae1dSRodney W. Grimes  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
640df8bae1dSRodney W. Grimes  * the first of which gives the bit number to be inspected (origin 1), and
641df8bae1dSRodney W. Grimes  * the next characters (up to a control character, i.e. a character <= 32),
642df8bae1dSRodney W. Grimes  * give the name of the register.  Thus:
643df8bae1dSRodney W. Grimes  *
644c5f282daSAlexey Dokuchaev  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
645df8bae1dSRodney W. Grimes  *
646df8bae1dSRodney W. Grimes  * would produce output:
647df8bae1dSRodney W. Grimes  *
648df8bae1dSRodney W. Grimes  *	reg=3<BITTWO,BITONE>
649df8bae1dSRodney W. Grimes  *
650120f0783SPoul-Henning Kamp  * XXX:  %D  -- Hexdump, takes pointer and separator string:
651120f0783SPoul-Henning Kamp  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
652120f0783SPoul-Henning Kamp  *		("%*D", len, ptr, " " -> XX XX XX XX ...
653df8bae1dSRodney W. Grimes  */
654791d77e0SPoul-Henning Kamp int
655791d77e0SPoul-Henning Kamp kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
656df8bae1dSRodney W. Grimes {
657791d77e0SPoul-Henning Kamp #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
658ad4f8dbdSArchie Cobbs 	char nbuf[MAXNBUF];
6593b1f7e7dSDag-Erling Smørgrav 	char *d;
6603b1f7e7dSDag-Erling Smørgrav 	const char *p, *percent, *q;
661120f0783SPoul-Henning Kamp 	u_char *up;
662791d77e0SPoul-Henning Kamp 	int ch, n;
6633b1f7e7dSDag-Erling Smørgrav 	uintmax_t num;
6647d921a01SPeter Wemm 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
66532869e71SNate Lawson 	int cflag, hflag, jflag, tflag, zflag;
666808a9c86SRyan Libby 	int bconv, dwidth, upper;
667df8bae1dSRodney W. Grimes 	char padc;
6681e7d2c47SPoul-Henning Kamp 	int stop = 0, retval = 0;
669791d77e0SPoul-Henning Kamp 
6703b1f7e7dSDag-Erling Smørgrav 	num = 0;
671b2037136SMatt Macy 	q = NULL;
672fe96d47dSPoul-Henning Kamp 	if (!func)
673791d77e0SPoul-Henning Kamp 		d = (char *) arg;
674791d77e0SPoul-Henning Kamp 	else
675fe96d47dSPoul-Henning Kamp 		d = NULL;
6768f5067baSDavid Greenman 
6778f5067baSDavid Greenman 	if (fmt == NULL)
6782336b9d7SBruce Evans 		fmt = "(fmt null)\n";
679b4b2f81eSPoul-Henning Kamp 
680120f0783SPoul-Henning Kamp 	if (radix < 2 || radix > 36)
681b4b2f81eSPoul-Henning Kamp 		radix = 10;
682b4b2f81eSPoul-Henning Kamp 
683df8bae1dSRodney W. Grimes 	for (;;) {
684df8bae1dSRodney W. Grimes 		padc = ' ';
685df8bae1dSRodney W. Grimes 		width = 0;
6861e7d2c47SPoul-Henning Kamp 		while ((ch = (u_char)*fmt++) != '%' || stop) {
687df8bae1dSRodney W. Grimes 			if (ch == '\0')
68858a24f79SPoul-Henning Kamp 				return (retval);
689791d77e0SPoul-Henning Kamp 			PCHAR(ch);
690df8bae1dSRodney W. Grimes 		}
6913b1f7e7dSDag-Erling Smørgrav 		percent = fmt - 1;
6927d921a01SPeter Wemm 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
693808a9c86SRyan Libby 		sign = 0; dot = 0; bconv = 0; dwidth = 0; upper = 0;
69432869e71SNate Lawson 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
695e0c95ed9SBruce Evans reswitch:	switch (ch = (u_char)*fmt++) {
6964830092aSPoul-Henning Kamp 		case '.':
6974830092aSPoul-Henning Kamp 			dot = 1;
6984830092aSPoul-Henning Kamp 			goto reswitch;
699791d77e0SPoul-Henning Kamp 		case '#':
700791d77e0SPoul-Henning Kamp 			sharpflag = 1;
701791d77e0SPoul-Henning Kamp 			goto reswitch;
702791d77e0SPoul-Henning Kamp 		case '+':
703791d77e0SPoul-Henning Kamp 			sign = 1;
704791d77e0SPoul-Henning Kamp 			goto reswitch;
705791d77e0SPoul-Henning Kamp 		case '-':
706791d77e0SPoul-Henning Kamp 			ladjust = 1;
707791d77e0SPoul-Henning Kamp 			goto reswitch;
708791d77e0SPoul-Henning Kamp 		case '%':
709791d77e0SPoul-Henning Kamp 			PCHAR(ch);
710791d77e0SPoul-Henning Kamp 			break;
711791d77e0SPoul-Henning Kamp 		case '*':
712ed71c342SPoul-Henning Kamp 			if (!dot) {
713791d77e0SPoul-Henning Kamp 				width = va_arg(ap, int);
714791d77e0SPoul-Henning Kamp 				if (width < 0) {
715791d77e0SPoul-Henning Kamp 					ladjust = !ladjust;
716791d77e0SPoul-Henning Kamp 					width = -width;
717791d77e0SPoul-Henning Kamp 				}
718ed71c342SPoul-Henning Kamp 			} else {
719ed71c342SPoul-Henning Kamp 				dwidth = va_arg(ap, int);
720ed71c342SPoul-Henning Kamp 			}
721791d77e0SPoul-Henning Kamp 			goto reswitch;
722df8bae1dSRodney W. Grimes 		case '0':
7234f20e4b1SPoul-Henning Kamp 			if (!dot) {
724df8bae1dSRodney W. Grimes 				padc = '0';
725df8bae1dSRodney W. Grimes 				goto reswitch;
7264f20e4b1SPoul-Henning Kamp 			}
7279295517aSMark Johnston 			/* FALLTHROUGH */
728df8bae1dSRodney W. Grimes 		case '1': case '2': case '3': case '4':
729df8bae1dSRodney W. Grimes 		case '5': case '6': case '7': case '8': case '9':
7304f20e4b1SPoul-Henning Kamp 				for (n = 0;; ++fmt) {
7314f20e4b1SPoul-Henning Kamp 					n = n * 10 + ch - '0';
732df8bae1dSRodney W. Grimes 					ch = *fmt;
733df8bae1dSRodney W. Grimes 					if (ch < '0' || ch > '9')
734df8bae1dSRodney W. Grimes 						break;
735df8bae1dSRodney W. Grimes 				}
7364f20e4b1SPoul-Henning Kamp 			if (dot)
7374f20e4b1SPoul-Henning Kamp 				dwidth = n;
7384f20e4b1SPoul-Henning Kamp 			else
7394f20e4b1SPoul-Henning Kamp 				width = n;
740df8bae1dSRodney W. Grimes 			goto reswitch;
741df8bae1dSRodney W. Grimes 		case 'b':
742808a9c86SRyan Libby 			ladjust = 1;
743808a9c86SRyan Libby 			bconv = 1;
744808a9c86SRyan Libby 			goto handle_nosign;
745df8bae1dSRodney W. Grimes 		case 'c':
746dd6ea7f7SConrad Meyer 			width -= 1;
747dd6ea7f7SConrad Meyer 
748dd6ea7f7SConrad Meyer 			if (!ladjust && width > 0)
749dd6ea7f7SConrad Meyer 				while (width--)
750dd6ea7f7SConrad Meyer 					PCHAR(padc);
751791d77e0SPoul-Henning Kamp 			PCHAR(va_arg(ap, int));
752dd6ea7f7SConrad Meyer 			if (ladjust && width > 0)
753dd6ea7f7SConrad Meyer 				while (width--)
754dd6ea7f7SConrad Meyer 					PCHAR(padc);
755df8bae1dSRodney W. Grimes 			break;
756120f0783SPoul-Henning Kamp 		case 'D':
757120f0783SPoul-Henning Kamp 			up = va_arg(ap, u_char *);
758120f0783SPoul-Henning Kamp 			p = va_arg(ap, char *);
759120f0783SPoul-Henning Kamp 			if (!width)
760120f0783SPoul-Henning Kamp 				width = 16;
761120f0783SPoul-Henning Kamp 			while(width--) {
762120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up >> 4));
763120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up & 0x0f));
764120f0783SPoul-Henning Kamp 				up++;
765120f0783SPoul-Henning Kamp 				if (width)
766120f0783SPoul-Henning Kamp 					for (q=p;*q;q++)
767120f0783SPoul-Henning Kamp 						PCHAR(*q);
768120f0783SPoul-Henning Kamp 			}
769120f0783SPoul-Henning Kamp 			break;
770df8bae1dSRodney W. Grimes 		case 'd':
771e0b74464SWarner Losh 		case 'i':
772df8bae1dSRodney W. Grimes 			base = 10;
7733b1f7e7dSDag-Erling Smørgrav 			sign = 1;
7743b1f7e7dSDag-Erling Smørgrav 			goto handle_sign;
77532869e71SNate Lawson 		case 'h':
77632869e71SNate Lawson 			if (hflag) {
77732869e71SNate Lawson 				hflag = 0;
77832869e71SNate Lawson 				cflag = 1;
77932869e71SNate Lawson 			} else
78032869e71SNate Lawson 				hflag = 1;
78132869e71SNate Lawson 			goto reswitch;
7823b1f7e7dSDag-Erling Smørgrav 		case 'j':
7833b1f7e7dSDag-Erling Smørgrav 			jflag = 1;
7843b1f7e7dSDag-Erling Smørgrav 			goto reswitch;
785791d77e0SPoul-Henning Kamp 		case 'l':
786301ca4ffSBrian Feldman 			if (lflag) {
787301ca4ffSBrian Feldman 				lflag = 0;
788301ca4ffSBrian Feldman 				qflag = 1;
789301ca4ffSBrian Feldman 			} else
790791d77e0SPoul-Henning Kamp 				lflag = 1;
791791d77e0SPoul-Henning Kamp 			goto reswitch;
7923b1f7e7dSDag-Erling Smørgrav 		case 'n':
793937b352eSEd Maste 			/*
794937b352eSEd Maste 			 * We do not support %n in kernel, but consume the
795937b352eSEd Maste 			 * argument.
796937b352eSEd Maste 			 */
7973b1f7e7dSDag-Erling Smørgrav 			if (jflag)
798937b352eSEd Maste 				(void)va_arg(ap, intmax_t *);
7993b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
800937b352eSEd Maste 				(void)va_arg(ap, quad_t *);
8017d921a01SPeter Wemm 			else if (lflag)
802937b352eSEd Maste 				(void)va_arg(ap, long *);
8034578a2e6SMaxime Henrion 			else if (zflag)
804937b352eSEd Maste 				(void)va_arg(ap, size_t *);
80532869e71SNate Lawson 			else if (hflag)
806937b352eSEd Maste 				(void)va_arg(ap, short *);
80732869e71SNate Lawson 			else if (cflag)
808937b352eSEd Maste 				(void)va_arg(ap, char *);
8097d921a01SPeter Wemm 			else
810937b352eSEd Maste 				(void)va_arg(ap, int *);
8113b1f7e7dSDag-Erling Smørgrav 			break;
8123b1f7e7dSDag-Erling Smørgrav 		case 'o':
813df8bae1dSRodney W. Grimes 			base = 8;
8143b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
81512d17f65SPoul-Henning Kamp 		case 'p':
81612d17f65SPoul-Henning Kamp 			base = 16;
817c41141b0SBruce Evans 			sharpflag = (width == 0);
8183b1f7e7dSDag-Erling Smørgrav 			sign = 0;
8193b1f7e7dSDag-Erling Smørgrav 			num = (uintptr_t)va_arg(ap, void *);
8203b1f7e7dSDag-Erling Smørgrav 			goto number;
8217d921a01SPeter Wemm 		case 'q':
8227d921a01SPeter Wemm 			qflag = 1;
8237d921a01SPeter Wemm 			goto reswitch;
824e0c38587SBruce Evans 		case 'r':
825e0c38587SBruce Evans 			base = radix;
8263b1f7e7dSDag-Erling Smørgrav 			if (sign)
8273b1f7e7dSDag-Erling Smørgrav 				goto handle_sign;
8283b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
829791d77e0SPoul-Henning Kamp 		case 's':
830791d77e0SPoul-Henning Kamp 			p = va_arg(ap, char *);
831791d77e0SPoul-Henning Kamp 			if (p == NULL)
832791d77e0SPoul-Henning Kamp 				p = "(null)";
8334830092aSPoul-Henning Kamp 			if (!dot)
8344830092aSPoul-Henning Kamp 				n = strlen (p);
8354830092aSPoul-Henning Kamp 			else
8364f20e4b1SPoul-Henning Kamp 				for (n = 0; n < dwidth && p[n]; n++)
8374830092aSPoul-Henning Kamp 					continue;
8384f20e4b1SPoul-Henning Kamp 
8394830092aSPoul-Henning Kamp 			width -= n;
8404f20e4b1SPoul-Henning Kamp 
841791d77e0SPoul-Henning Kamp 			if (!ladjust && width > 0)
842791d77e0SPoul-Henning Kamp 				while (width--)
843791d77e0SPoul-Henning Kamp 					PCHAR(padc);
8444830092aSPoul-Henning Kamp 			while (n--)
845791d77e0SPoul-Henning Kamp 				PCHAR(*p++);
846791d77e0SPoul-Henning Kamp 			if (ladjust && width > 0)
847791d77e0SPoul-Henning Kamp 				while (width--)
848791d77e0SPoul-Henning Kamp 					PCHAR(padc);
849791d77e0SPoul-Henning Kamp 			break;
8502bb95458SMaxime Henrion 		case 't':
8512bb95458SMaxime Henrion 			tflag = 1;
8522bb95458SMaxime Henrion 			goto reswitch;
853f53dbe97SBruce Evans 		case 'u':
854f53dbe97SBruce Evans 			base = 10;
8553b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
856aa998012SMike Smith 		case 'X':
8570d84d9ebSJung-uk Kim 			upper = 1;
858679e4cdaSMarius Strobl 			/* FALLTHROUGH */
8590d84d9ebSJung-uk Kim 		case 'x':
860df8bae1dSRodney W. Grimes 			base = 16;
8613b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
8624578a2e6SMaxime Henrion 		case 'y':
863e0c38587SBruce Evans 			base = 16;
86485594430SJohn Baldwin 			sign = 1;
8653b1f7e7dSDag-Erling Smørgrav 			goto handle_sign;
8664578a2e6SMaxime Henrion 		case 'z':
8674578a2e6SMaxime Henrion 			zflag = 1;
8684578a2e6SMaxime Henrion 			goto reswitch;
8693b1f7e7dSDag-Erling Smørgrav handle_nosign:
8703b1f7e7dSDag-Erling Smørgrav 			sign = 0;
8713b1f7e7dSDag-Erling Smørgrav 			if (jflag)
8723b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, uintmax_t);
8733b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
8743b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_quad_t);
8752bb95458SMaxime Henrion 			else if (tflag)
8762bb95458SMaxime Henrion 				num = va_arg(ap, ptrdiff_t);
8773b1f7e7dSDag-Erling Smørgrav 			else if (lflag)
8783b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_long);
8794578a2e6SMaxime Henrion 			else if (zflag)
8804578a2e6SMaxime Henrion 				num = va_arg(ap, size_t);
88132869e71SNate Lawson 			else if (hflag)
88232869e71SNate Lawson 				num = (u_short)va_arg(ap, int);
88332869e71SNate Lawson 			else if (cflag)
88432869e71SNate Lawson 				num = (u_char)va_arg(ap, int);
8853b1f7e7dSDag-Erling Smørgrav 			else
8863b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, u_int);
887808a9c86SRyan Libby 			if (bconv) {
888808a9c86SRyan Libby 				q = va_arg(ap, char *);
889808a9c86SRyan Libby 				base = *q++;
890808a9c86SRyan Libby 			}
891e0c38587SBruce Evans 			goto number;
8923b1f7e7dSDag-Erling Smørgrav handle_sign:
8933b1f7e7dSDag-Erling Smørgrav 			if (jflag)
8943b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, intmax_t);
8953b1f7e7dSDag-Erling Smørgrav 			else if (qflag)
8963b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, quad_t);
8972bb95458SMaxime Henrion 			else if (tflag)
8982bb95458SMaxime Henrion 				num = va_arg(ap, ptrdiff_t);
8993b1f7e7dSDag-Erling Smørgrav 			else if (lflag)
9003b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, long);
9014578a2e6SMaxime Henrion 			else if (zflag)
902e1088cdcSXin LI 				num = va_arg(ap, ssize_t);
90332869e71SNate Lawson 			else if (hflag)
90432869e71SNate Lawson 				num = (short)va_arg(ap, int);
90532869e71SNate Lawson 			else if (cflag)
90632869e71SNate Lawson 				num = (char)va_arg(ap, int);
9073b1f7e7dSDag-Erling Smørgrav 			else
9083b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, int);
9097d921a01SPeter Wemm number:
9103b1f7e7dSDag-Erling Smørgrav 			if (sign && (intmax_t)num < 0) {
9117d921a01SPeter Wemm 				neg = 1;
9123b1f7e7dSDag-Erling Smørgrav 				num = -(intmax_t)num;
9137d921a01SPeter Wemm 			}
9144624e08aSJung-uk Kim 			p = ksprintn(nbuf, num, base, &n, upper);
9154624e08aSJung-uk Kim 			tmp = 0;
9163b1f7e7dSDag-Erling Smørgrav 			if (sharpflag && num != 0) {
917791d77e0SPoul-Henning Kamp 				if (base == 8)
918791d77e0SPoul-Henning Kamp 					tmp++;
919791d77e0SPoul-Henning Kamp 				else if (base == 16)
920791d77e0SPoul-Henning Kamp 					tmp += 2;
921791d77e0SPoul-Henning Kamp 			}
922791d77e0SPoul-Henning Kamp 			if (neg)
923791d77e0SPoul-Henning Kamp 				tmp++;
924791d77e0SPoul-Henning Kamp 
9254624e08aSJung-uk Kim 			if (!ladjust && padc == '0')
9264624e08aSJung-uk Kim 				dwidth = width - tmp;
9274a82f108SJung-uk Kim 			width -= tmp + imax(dwidth, n);
9284624e08aSJung-uk Kim 			dwidth -= n;
9294624e08aSJung-uk Kim 			if (!ladjust)
9304624e08aSJung-uk Kim 				while (width-- > 0)
9314624e08aSJung-uk Kim 					PCHAR(' ');
932791d77e0SPoul-Henning Kamp 			if (neg)
933791d77e0SPoul-Henning Kamp 				PCHAR('-');
9343b1f7e7dSDag-Erling Smørgrav 			if (sharpflag && num != 0) {
935791d77e0SPoul-Henning Kamp 				if (base == 8) {
936791d77e0SPoul-Henning Kamp 					PCHAR('0');
937791d77e0SPoul-Henning Kamp 				} else if (base == 16) {
938791d77e0SPoul-Henning Kamp 					PCHAR('0');
939791d77e0SPoul-Henning Kamp 					PCHAR('x');
940791d77e0SPoul-Henning Kamp 				}
941791d77e0SPoul-Henning Kamp 			}
9424624e08aSJung-uk Kim 			while (dwidth-- > 0)
9434624e08aSJung-uk Kim 				PCHAR('0');
944791d77e0SPoul-Henning Kamp 
945797f2d22SPoul-Henning Kamp 			while (*p)
946791d77e0SPoul-Henning Kamp 				PCHAR(*p--);
947791d77e0SPoul-Henning Kamp 
948808a9c86SRyan Libby 			if (bconv && num != 0) {
949808a9c86SRyan Libby 				/* %b conversion flag format. */
950808a9c86SRyan Libby 				tmp = retval;
951808a9c86SRyan Libby 				while (*q) {
952808a9c86SRyan Libby 					n = *q++;
953808a9c86SRyan Libby 					if (num & (1 << (n - 1))) {
954808a9c86SRyan Libby 						PCHAR(retval != tmp ?
955808a9c86SRyan Libby 						    ',' : '<');
956808a9c86SRyan Libby 						for (; (n = *q) > ' '; ++q)
957808a9c86SRyan Libby 							PCHAR(n);
958808a9c86SRyan Libby 					} else
959808a9c86SRyan Libby 						for (; *q > ' '; ++q)
960808a9c86SRyan Libby 							continue;
961808a9c86SRyan Libby 				}
962808a9c86SRyan Libby 				if (retval != tmp) {
963808a9c86SRyan Libby 					PCHAR('>');
964808a9c86SRyan Libby 					width -= retval - tmp;
965808a9c86SRyan Libby 				}
966808a9c86SRyan Libby 			}
967808a9c86SRyan Libby 
9684624e08aSJung-uk Kim 			if (ladjust)
9694624e08aSJung-uk Kim 				while (width-- > 0)
9704624e08aSJung-uk Kim 					PCHAR(' ');
971791d77e0SPoul-Henning Kamp 
972df8bae1dSRodney W. Grimes 			break;
973df8bae1dSRodney W. Grimes 		default:
9743b1f7e7dSDag-Erling Smørgrav 			while (percent < fmt)
9753b1f7e7dSDag-Erling Smørgrav 				PCHAR(*percent++);
9761e7d2c47SPoul-Henning Kamp 			/*
9772809a6dfSBryan Drewery 			 * Since we ignore a formatting argument it is no
9781e7d2c47SPoul-Henning Kamp 			 * longer safe to obey the remaining formatting
9791e7d2c47SPoul-Henning Kamp 			 * arguments as the arguments will no longer match
9801e7d2c47SPoul-Henning Kamp 			 * the format specs.
9811e7d2c47SPoul-Henning Kamp 			 */
9821e7d2c47SPoul-Henning Kamp 			stop = 1;
983791d77e0SPoul-Henning Kamp 			break;
984df8bae1dSRodney W. Grimes 		}
985df8bae1dSRodney W. Grimes 	}
986791d77e0SPoul-Henning Kamp #undef PCHAR
987df8bae1dSRodney W. Grimes }
988df8bae1dSRodney W. Grimes 
989df8bae1dSRodney W. Grimes /*
990e2a09b26SPoul-Henning Kamp  * Put character in log buffer with a particular priority.
991df8bae1dSRodney W. Grimes  */
992df8bae1dSRodney W. Grimes static void
993e2a09b26SPoul-Henning Kamp msglogchar(int c, int pri)
994e2a09b26SPoul-Henning Kamp {
995e2a09b26SPoul-Henning Kamp 	static int lastpri = -1;
996e2a09b26SPoul-Henning Kamp 	static int dangling;
997e2a09b26SPoul-Henning Kamp 	char nbuf[MAXNBUF];
998e2a09b26SPoul-Henning Kamp 	char *p;
999e2a09b26SPoul-Henning Kamp 
1000e2a09b26SPoul-Henning Kamp 	if (!msgbufmapped)
1001e2a09b26SPoul-Henning Kamp 		return;
1002e2a09b26SPoul-Henning Kamp 	if (c == '\0' || c == '\r')
1003e2a09b26SPoul-Henning Kamp 		return;
1004e2a09b26SPoul-Henning Kamp 	if (pri != -1 && pri != lastpri) {
1005e2a09b26SPoul-Henning Kamp 		if (dangling) {
10064784a469SIan Dowse 			msgbuf_addchar(msgbufp, '\n');
1007e2a09b26SPoul-Henning Kamp 			dangling = 0;
1008e2a09b26SPoul-Henning Kamp 		}
10094784a469SIan Dowse 		msgbuf_addchar(msgbufp, '<');
10100d84d9ebSJung-uk Kim 		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL, 0); *p;)
10114784a469SIan Dowse 			msgbuf_addchar(msgbufp, *p--);
10124784a469SIan Dowse 		msgbuf_addchar(msgbufp, '>');
1013e2a09b26SPoul-Henning Kamp 		lastpri = pri;
1014e2a09b26SPoul-Henning Kamp 	}
10154784a469SIan Dowse 	msgbuf_addchar(msgbufp, c);
1016e2a09b26SPoul-Henning Kamp 	if (c == '\n') {
1017e2a09b26SPoul-Henning Kamp 		dangling = 0;
1018e2a09b26SPoul-Henning Kamp 		lastpri = -1;
1019e2a09b26SPoul-Henning Kamp 	} else {
1020e2a09b26SPoul-Henning Kamp 		dangling = 1;
1021e2a09b26SPoul-Henning Kamp 	}
1022e2a09b26SPoul-Henning Kamp }
1023e2a09b26SPoul-Henning Kamp 
1024d42a4eb5SKenneth D. Merry static void
1025d42a4eb5SKenneth D. Merry msglogstr(char *str, int pri, int filter_cr)
1026d42a4eb5SKenneth D. Merry {
1027d42a4eb5SKenneth D. Merry 	if (!msgbufmapped)
1028d42a4eb5SKenneth D. Merry 		return;
1029d42a4eb5SKenneth D. Merry 
1030d42a4eb5SKenneth D. Merry 	msgbuf_addstr(msgbufp, pri, str, filter_cr);
1031d42a4eb5SKenneth D. Merry }
1032d42a4eb5SKenneth D. Merry 
1033e796e00dSPoul-Henning Kamp void
103401ee4395SThomas Moestl msgbufinit(void *ptr, int size)
1035e796e00dSPoul-Henning Kamp {
1036e796e00dSPoul-Henning Kamp 	char *cp;
10370915d9d0SKyle Evans 	static struct msgbuf *oldp = NULL;
1038170bc291SKyle Evans 	bool print_boot_tag;
1039e796e00dSPoul-Henning Kamp 
1040cca8f980SIan Dowse 	size -= sizeof(*msgbufp);
1041e796e00dSPoul-Henning Kamp 	cp = (char *)ptr;
1042170bc291SKyle Evans 	print_boot_tag = !msgbufmapped;
10432a4650ccSKyle Evans 	/* Attempt to fetch kern.boot_tag tunable on first mapping */
10442a4650ccSKyle Evans 	if (!msgbufmapped)
10452a4650ccSKyle Evans 		TUNABLE_STR_FETCH("kern.boot_tag", current_boot_tag,
1046240fcda1SKyle Evans 		    sizeof(current_boot_tag));
1047cca8f980SIan Dowse 	msgbufp = (struct msgbuf *)(cp + size);
10484784a469SIan Dowse 	msgbuf_reinit(msgbufp, cp, size);
1049eb9d435aSJonathan Lemon 	if (msgbufmapped && oldp != msgbufp)
10504784a469SIan Dowse 		msgbuf_copy(oldp, msgbufp);
105121aa6e83SKyle Evans 	msgbufmapped = true;
105245625675SKyle Evans 	if (print_boot_tag && *current_boot_tag != '\0')
1053170bc291SKyle Evans 		printf("%s\n", current_boot_tag);
1054eb9d435aSJonathan Lemon 	oldp = msgbufp;
1055e796e00dSPoul-Henning Kamp }
1056e796e00dSPoul-Henning Kamp 
1057948d3d94SThomas Moestl /* Sysctls for accessing/clearing the msgbuf */
1058948d3d94SThomas Moestl static int
1059948d3d94SThomas Moestl sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
1060948d3d94SThomas Moestl {
10614784a469SIan Dowse 	char buf[128];
10624784a469SIan Dowse 	u_int seq;
10634784a469SIan Dowse 	int error, len;
1064948d3d94SThomas Moestl 
1065acd3428bSRobert Watson 	error = priv_check(req->td, PRIV_MSGBUF);
10666f3933faSRobert Watson 	if (error)
10676f3933faSRobert Watson 		return (error);
10686f3933faSRobert Watson 
10694784a469SIan Dowse 	/* Read the whole buffer, one chunk at a time. */
1070ca1d2f65SEd Schouten 	mtx_lock(&msgbuf_lock);
10714784a469SIan Dowse 	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
1072ca1d2f65SEd Schouten 	for (;;) {
1073ca1d2f65SEd Schouten 		len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
1074ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
1075ca1d2f65SEd Schouten 		if (len == 0)
1076e5197e3aSIan Lepore 			return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
1077ca1d2f65SEd Schouten 
10784784a469SIan Dowse 		error = sysctl_handle_opaque(oidp, buf, len, req);
1079948d3d94SThomas Moestl 		if (error)
1080948d3d94SThomas Moestl 			return (error);
1081ca1d2f65SEd Schouten 
1082ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
1083948d3d94SThomas Moestl 	}
1084948d3d94SThomas Moestl }
1085948d3d94SThomas Moestl 
1086ca1d2f65SEd Schouten SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
1087ca1d2f65SEd Schouten     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
10884592c621SWarner Losh     NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
1089948d3d94SThomas Moestl 
10904784a469SIan Dowse static int msgbuf_clearflag;
1091948d3d94SThomas Moestl 
1092948d3d94SThomas Moestl static int
1093948d3d94SThomas Moestl sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
1094948d3d94SThomas Moestl {
1095948d3d94SThomas Moestl 	int error;
1096948d3d94SThomas Moestl 	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1097948d3d94SThomas Moestl 	if (!error && req->newptr) {
1098ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
10994784a469SIan Dowse 		msgbuf_clear(msgbufp);
1100ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
11014784a469SIan Dowse 		msgbuf_clearflag = 0;
1102948d3d94SThomas Moestl 	}
1103948d3d94SThomas Moestl 	return (error);
1104948d3d94SThomas Moestl }
1105948d3d94SThomas Moestl 
1106948d3d94SThomas Moestl SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
1107ca1d2f65SEd Schouten     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE,
1108ca1d2f65SEd Schouten     &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I",
1109ca1d2f65SEd Schouten     "Clear kernel message buffer");
1110948d3d94SThomas Moestl 
1111e796e00dSPoul-Henning Kamp #ifdef DDB
1112e796e00dSPoul-Henning Kamp 
1113e796e00dSPoul-Henning Kamp DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
1114e796e00dSPoul-Henning Kamp {
111519e9205aSJohn Baldwin 	int i, j;
1116e796e00dSPoul-Henning Kamp 
1117e796e00dSPoul-Henning Kamp 	if (!msgbufmapped) {
1118e796e00dSPoul-Henning Kamp 		db_printf("msgbuf not mapped yet\n");
1119e796e00dSPoul-Henning Kamp 		return;
1120e796e00dSPoul-Henning Kamp 	}
1121e796e00dSPoul-Henning Kamp 	db_printf("msgbufp = %p\n", msgbufp);
11224784a469SIan Dowse 	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
11234784a469SIan Dowse 	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
11244784a469SIan Dowse 	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
112519e9205aSJohn Baldwin 	for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) {
11264784a469SIan Dowse 		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
1127e796e00dSPoul-Henning Kamp 		db_printf("%c", msgbufp->msg_ptr[j]);
1128e796e00dSPoul-Henning Kamp 	}
1129e796e00dSPoul-Henning Kamp 	db_printf("\n");
1130e796e00dSPoul-Henning Kamp }
1131e796e00dSPoul-Henning Kamp 
1132e796e00dSPoul-Henning Kamp #endif /* DDB */
113377411499SScott Long 
113477411499SScott Long void
113530a1695bSPoul-Henning Kamp hexdump(const void *ptr, int length, const char *hdr, int flags)
113677411499SScott Long {
113777411499SScott Long 	int i, j, k;
113877411499SScott Long 	int cols;
113930a1695bSPoul-Henning Kamp 	const unsigned char *cp;
114077411499SScott Long 	char delim;
114177411499SScott Long 
114277411499SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
114377411499SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
114477411499SScott Long 	else
114577411499SScott Long 		delim = ' ';
114677411499SScott Long 
114777411499SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
114877411499SScott Long 		cols = flags & HD_COLUMN_MASK;
114977411499SScott Long 	else
115077411499SScott Long 		cols = 16;
115177411499SScott Long 
115277411499SScott Long 	cp = ptr;
115377411499SScott Long 	for (i = 0; i < length; i+= cols) {
115477411499SScott Long 		if (hdr != NULL)
115577411499SScott Long 			printf("%s", hdr);
115677411499SScott Long 
115777411499SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
115877411499SScott Long 			printf("%04x  ", i);
115977411499SScott Long 
116077411499SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
116177411499SScott Long 			for (j = 0; j < cols; j++) {
116277411499SScott Long 				k = i + j;
116377411499SScott Long 				if (k < length)
116477411499SScott Long 					printf("%c%02x", delim, cp[k]);
116577411499SScott Long 				else
116677411499SScott Long 					printf("   ");
116777411499SScott Long 			}
116877411499SScott Long 		}
116977411499SScott Long 
117077411499SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
117177411499SScott Long 			printf("  |");
117277411499SScott Long 			for (j = 0; j < cols; j++) {
117377411499SScott Long 				k = i + j;
117477411499SScott Long 				if (k >= length)
117577411499SScott Long 					printf(" ");
117677411499SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
117777411499SScott Long 					printf("%c", cp[k]);
117877411499SScott Long 				else
117977411499SScott Long 					printf(".");
118077411499SScott Long 			}
11816ec6fb9bSScott Long 			printf("|");
118277411499SScott Long 		}
11836ec6fb9bSScott Long 		printf("\n");
118477411499SScott Long 	}
118577411499SScott Long }
11865672fac9SKenneth D. Merry #endif /* _KERNEL */
11875672fac9SKenneth D. Merry 
11885672fac9SKenneth D. Merry void
11895672fac9SKenneth D. Merry sbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
11905672fac9SKenneth D. Merry 	     int flags)
11915672fac9SKenneth D. Merry {
11925672fac9SKenneth D. Merry 	int i, j, k;
11935672fac9SKenneth D. Merry 	int cols;
11945672fac9SKenneth D. Merry 	const unsigned char *cp;
11955672fac9SKenneth D. Merry 	char delim;
11965672fac9SKenneth D. Merry 
11975672fac9SKenneth D. Merry 	if ((flags & HD_DELIM_MASK) != 0)
11985672fac9SKenneth D. Merry 		delim = (flags & HD_DELIM_MASK) >> 8;
11995672fac9SKenneth D. Merry 	else
12005672fac9SKenneth D. Merry 		delim = ' ';
12015672fac9SKenneth D. Merry 
12025672fac9SKenneth D. Merry 	if ((flags & HD_COLUMN_MASK) != 0)
12035672fac9SKenneth D. Merry 		cols = flags & HD_COLUMN_MASK;
12045672fac9SKenneth D. Merry 	else
12055672fac9SKenneth D. Merry 		cols = 16;
12065672fac9SKenneth D. Merry 
12075672fac9SKenneth D. Merry 	cp = ptr;
12085672fac9SKenneth D. Merry 	for (i = 0; i < length; i+= cols) {
12095672fac9SKenneth D. Merry 		if (hdr != NULL)
12105672fac9SKenneth D. Merry 			sbuf_printf(sb, "%s", hdr);
12115672fac9SKenneth D. Merry 
12125672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_COUNT) == 0)
12135672fac9SKenneth D. Merry 			sbuf_printf(sb, "%04x  ", i);
12145672fac9SKenneth D. Merry 
12155672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_HEX) == 0) {
12165672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12175672fac9SKenneth D. Merry 				k = i + j;
12185672fac9SKenneth D. Merry 				if (k < length)
12195672fac9SKenneth D. Merry 					sbuf_printf(sb, "%c%02x", delim, cp[k]);
12205672fac9SKenneth D. Merry 				else
12215672fac9SKenneth D. Merry 					sbuf_printf(sb, "   ");
12225672fac9SKenneth D. Merry 			}
12235672fac9SKenneth D. Merry 		}
12245672fac9SKenneth D. Merry 
12255672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_CHARS) == 0) {
12265672fac9SKenneth D. Merry 			sbuf_printf(sb, "  |");
12275672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12285672fac9SKenneth D. Merry 				k = i + j;
12295672fac9SKenneth D. Merry 				if (k >= length)
12305672fac9SKenneth D. Merry 					sbuf_printf(sb, " ");
12315672fac9SKenneth D. Merry 				else if (cp[k] >= ' ' && cp[k] <= '~')
12325672fac9SKenneth D. Merry 					sbuf_printf(sb, "%c", cp[k]);
12335672fac9SKenneth D. Merry 				else
12345672fac9SKenneth D. Merry 					sbuf_printf(sb, ".");
12355672fac9SKenneth D. Merry 			}
12365672fac9SKenneth D. Merry 			sbuf_printf(sb, "|");
12375672fac9SKenneth D. Merry 		}
12385672fac9SKenneth D. Merry 		sbuf_printf(sb, "\n");
12395672fac9SKenneth D. Merry 	}
12405672fac9SKenneth D. Merry }
12415672fac9SKenneth D. Merry 
1242492fe1b7SKonstantin Belousov #ifdef _KERNEL
12439837947bSKonstantin Belousov void
12449837947bSKonstantin Belousov counted_warning(unsigned *counter, const char *msg)
12459837947bSKonstantin Belousov {
12469837947bSKonstantin Belousov 	struct thread *td;
12479837947bSKonstantin Belousov 	unsigned c;
12489837947bSKonstantin Belousov 
12499837947bSKonstantin Belousov 	for (;;) {
12509837947bSKonstantin Belousov 		c = *counter;
12519837947bSKonstantin Belousov 		if (c == 0)
12529837947bSKonstantin Belousov 			break;
12539837947bSKonstantin Belousov 		if (atomic_cmpset_int(counter, c, c - 1)) {
12549837947bSKonstantin Belousov 			td = curthread;
12559837947bSKonstantin Belousov 			log(LOG_INFO, "pid %d (%s) %s%s\n",
12569837947bSKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, msg,
12579837947bSKonstantin Belousov 			    c > 1 ? "" : " - not logging anymore");
12589837947bSKonstantin Belousov 			break;
12599837947bSKonstantin Belousov 		}
12609837947bSKonstantin Belousov 	}
12619837947bSKonstantin Belousov }
1262492fe1b7SKonstantin Belousov #endif
1263388f3ce6SScott Long 
1264388f3ce6SScott Long #ifdef _KERNEL
1265388f3ce6SScott Long void
1266388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1267388f3ce6SScott Long {
1268388f3ce6SScott Long 
1269388f3ce6SScott Long 	prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1);
1270388f3ce6SScott Long }
1271388f3ce6SScott Long #else
1272388f3ce6SScott Long void
1273388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1274388f3ce6SScott Long {
1275388f3ce6SScott Long 
1276388f3ce6SScott Long 	printf("%s", sbuf_data(sb));
1277388f3ce6SScott Long }
1278388f3ce6SScott Long #endif
12797d7db529SConrad Meyer 
12807d7db529SConrad Meyer int
12817d7db529SConrad Meyer sbuf_printf_drain(void *arg, const char *data, int len)
12827d7db529SConrad Meyer {
12837d7db529SConrad Meyer 	size_t *retvalptr;
12847d7db529SConrad Meyer 	int r;
12857d7db529SConrad Meyer #ifdef _KERNEL
12867d7db529SConrad Meyer 	char *dataptr;
12877d7db529SConrad Meyer 	char oldchr;
12887d7db529SConrad Meyer 
12897d7db529SConrad Meyer 	/*
12907d7db529SConrad Meyer 	 * This is allowed as an extra byte is always resvered for
12917d7db529SConrad Meyer 	 * terminating NUL byte.  Save and restore the byte because
12927d7db529SConrad Meyer 	 * we might be flushing a record, and there may be valid
12937d7db529SConrad Meyer 	 * data after the buffer.
12947d7db529SConrad Meyer 	 */
12957d7db529SConrad Meyer 	oldchr = data[len];
12967d7db529SConrad Meyer 	dataptr = __DECONST(char *, data);
12977d7db529SConrad Meyer 	dataptr[len] = '\0';
12987d7db529SConrad Meyer 
12997d7db529SConrad Meyer 	prf_putbuf(dataptr, TOLOG | TOCONS, -1);
13007d7db529SConrad Meyer 	r = len;
13017d7db529SConrad Meyer 
13027d7db529SConrad Meyer 	dataptr[len] = oldchr;
13037d7db529SConrad Meyer 
13047d7db529SConrad Meyer #else /* !_KERNEL */
13057d7db529SConrad Meyer 
13067d7db529SConrad Meyer 	r = printf("%.*s", len, data);
13077d7db529SConrad Meyer 	if (r < 0)
13087d7db529SConrad Meyer 		return (-errno);
13097d7db529SConrad Meyer 
13107d7db529SConrad Meyer #endif
13117d7db529SConrad Meyer 
13127d7db529SConrad Meyer 	retvalptr = arg;
13137d7db529SConrad Meyer 	if (retvalptr != NULL)
13147d7db529SConrad Meyer 		*retvalptr += r;
13157d7db529SConrad Meyer 
13167d7db529SConrad Meyer 	return (r);
13177d7db529SConrad Meyer }
1318