xref: /freebsd/sys/kern/subr_prf.c (revision 07d90ee0a62110e5161bb0b8a3a0b1b9d2beabad)
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 
37677b542eSDavid E. O'Brien #include <sys/cdefs.h>
385672fac9SKenneth D. Merry #ifdef _KERNEL
393ae59505SPoul-Henning Kamp #include "opt_ddb.h"
40e0b65125SJohn Birrell #include "opt_printf.h"
415672fac9SKenneth D. Merry #endif  /* _KERNEL */
423ae59505SPoul-Henning Kamp 
43df8bae1dSRodney W. Grimes #include <sys/param.h>
445672fac9SKenneth D. Merry #ifdef _KERNEL
45df8bae1dSRodney W. Grimes #include <sys/systm.h>
46f591779bSSeigo Tanimura #include <sys/lock.h>
4782ebaee7SMarcel Moolenaar #include <sys/kdb.h>
48f591779bSSeigo Tanimura #include <sys/mutex.h>
49f591779bSSeigo Tanimura #include <sys/sx.h>
50e796e00dSPoul-Henning Kamp #include <sys/kernel.h>
51df8bae1dSRodney W. Grimes #include <sys/msgbuf.h>
52a1c995b6SPoul-Henning Kamp #include <sys/malloc.h>
53acd3428bSRobert Watson #include <sys/priv.h>
54df8bae1dSRodney W. Grimes #include <sys/proc.h>
552bb95458SMaxime Henrion #include <sys/stddef.h>
5658a24f79SPoul-Henning Kamp #include <sys/sysctl.h>
579d6ae1e3SColin Percival #include <sys/tslog.h>
58df8bae1dSRodney W. Grimes #include <sys/tty.h>
59df8bae1dSRodney W. Grimes #include <sys/syslog.h>
60ce9edcf5SPoul-Henning Kamp #include <sys/cons.h>
61e2a09b26SPoul-Henning Kamp #include <sys/uio.h>
627d7db529SConrad Meyer #else /* !_KERNEL */
637d7db529SConrad Meyer #include <errno.h>
645672fac9SKenneth D. Merry #endif
650d84d9ebSJung-uk Kim #include <sys/ctype.h>
665672fac9SKenneth D. Merry #include <sys/sbuf.h>
67df8bae1dSRodney W. Grimes 
683ae59505SPoul-Henning Kamp #ifdef DDB
693ae59505SPoul-Henning Kamp #include <ddb/ddb.h>
703ae59505SPoul-Henning Kamp #endif
713ae59505SPoul-Henning Kamp 
72df8bae1dSRodney W. Grimes /*
73df8bae1dSRodney W. Grimes  * Note that stdarg.h and the ANSI style va_start macro is used for both
74df8bae1dSRodney W. Grimes  * ANSI and traditional C compilers.
75df8bae1dSRodney W. Grimes  */
7607f862a7SMarcel Moolenaar #ifdef _KERNEL
77df8bae1dSRodney W. Grimes #include <machine/stdarg.h>
7807f862a7SMarcel Moolenaar #else
7907f862a7SMarcel Moolenaar #include <stdarg.h>
8038e41e66SScott Long #endif
8138e41e66SScott Long 
8238e41e66SScott Long /*
8338e41e66SScott Long  * This is needed for sbuf_putbuf() when compiled into userland.  Due to the
8438e41e66SScott Long  * shared nature of this file, it's the only place to put it.
8538e41e66SScott Long  */
8638e41e66SScott Long #ifndef _KERNEL
87c4e92994SJung-uk Kim #include <stdio.h>
8807f862a7SMarcel Moolenaar #endif
89df8bae1dSRodney W. Grimes 
905672fac9SKenneth D. Merry #ifdef _KERNEL
915672fac9SKenneth D. Merry 
92df8bae1dSRodney W. Grimes #define TOCONS	0x01
93df8bae1dSRodney W. Grimes #define TOTTY	0x02
94df8bae1dSRodney W. Grimes #define TOLOG	0x04
95df8bae1dSRodney W. Grimes 
9682941964SPeter Wemm /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
973b1f7e7dSDag-Erling Smørgrav #define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
98df8bae1dSRodney W. Grimes 
998245f3f5SArchie Cobbs struct putchar_arg {
1008245f3f5SArchie Cobbs 	int	flags;
101e2a09b26SPoul-Henning Kamp 	int	pri;
1028245f3f5SArchie Cobbs 	struct	tty *tty;
1033d068827SJohn Birrell 	char	*p_bufr;
1043d068827SJohn Birrell 	size_t	n_bufr;
1053d068827SJohn Birrell 	char	*p_next;
1063d068827SJohn Birrell 	size_t	remain;
1078245f3f5SArchie Cobbs };
1088245f3f5SArchie Cobbs 
1098245f3f5SArchie Cobbs struct snprintf_arg {
1108245f3f5SArchie Cobbs 	char	*str;
1118245f3f5SArchie Cobbs 	size_t	remain;
1128245f3f5SArchie Cobbs };
1138245f3f5SArchie Cobbs 
114e2a09b26SPoul-Henning Kamp extern	int log_open;
115e2a09b26SPoul-Henning Kamp 
116e2a09b26SPoul-Henning Kamp static void  msglogchar(int c, int pri);
117d42a4eb5SKenneth D. Merry static void  msglogstr(char *str, int pri, int filter_cr);
118a264594dSAlexander Motin static void  prf_putbuf(char *bufr, int flags, int pri);
1194d77a549SAlfred Perlstein static void  putchar(int ch, void *arg);
1200d84d9ebSJung-uk Kim static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
1214d77a549SAlfred Perlstein static void  snprintf_func(int ch, void *arg);
122df8bae1dSRodney W. Grimes 
12321aa6e83SKyle Evans static bool msgbufmapped;		/* Set when safe to use msgbuf */
124e2a09b26SPoul-Henning Kamp int msgbuftrigger;
125fb3cc1c3SBruce Evans struct msgbuf *msgbufp;
126df8bae1dSRodney W. Grimes 
1272a4650ccSKyle Evans #ifndef BOOT_TAG_SZ
1282a4650ccSKyle Evans #define	BOOT_TAG_SZ	32
1292a4650ccSKyle Evans #endif
1302a4650ccSKyle Evans #ifndef BOOT_TAG
1312a4650ccSKyle Evans /* Tag used to mark the start of a boot in dmesg */
1322a4650ccSKyle Evans #define	BOOT_TAG	"---<<BOOT>>---"
1332a4650ccSKyle Evans #endif
1342a4650ccSKyle Evans 
1352a4650ccSKyle Evans static char current_boot_tag[BOOT_TAG_SZ + 1] = BOOT_TAG;
1362a4650ccSKyle Evans SYSCTL_STRING(_kern, OID_AUTO, boot_tag, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
1372a4650ccSKyle Evans     current_boot_tag, 0, "Tag added to dmesg at start of boot");
1382a4650ccSKyle Evans 
139dbe620d3SDavid Malone static int log_console_output = 1;
140af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
141af3b2549SHans Petter Selasky     &log_console_output, 0, "Duplicate console output to the syslog");
1428e1b7974SBrian Feldman 
143d42a4eb5SKenneth D. Merry /*
144d42a4eb5SKenneth D. Merry  * See the comment in log_console() below for more explanation of this.
145d42a4eb5SKenneth D. Merry  */
146af3b2549SHans Petter Selasky static int log_console_add_linefeed;
147af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
148af3b2549SHans Petter Selasky     &log_console_add_linefeed, 0, "log_console() adds extra newlines");
149d42a4eb5SKenneth D. Merry 
150af3b2549SHans Petter Selasky static int always_console_output;
151af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
152af3b2549SHans Petter Selasky     &always_console_output, 0, "Always output to console despite TIOCCONS");
153dbe620d3SDavid Malone 
154df8bae1dSRodney W. Grimes /*
155df8bae1dSRodney W. Grimes  * Warn that a system table is full.
156df8bae1dSRodney W. Grimes  */
157df8bae1dSRodney W. Grimes void
tablefull(const char * tab)158e2a09b26SPoul-Henning Kamp tablefull(const char *tab)
159df8bae1dSRodney W. Grimes {
160df8bae1dSRodney W. Grimes 
161df8bae1dSRodney W. Grimes 	log(LOG_ERR, "%s: table is full\n", tab);
162df8bae1dSRodney W. Grimes }
163df8bae1dSRodney W. Grimes 
164df8bae1dSRodney W. Grimes /*
165df8bae1dSRodney W. Grimes  * Uprintf prints to the controlling terminal for the current process.
166df8bae1dSRodney W. Grimes  */
167f1550d9dSDoug Rabson int
uprintf(const char * fmt,...)168df8bae1dSRodney W. Grimes uprintf(const char *fmt, ...)
169df8bae1dSRodney W. Grimes {
170df8bae1dSRodney W. Grimes 	va_list ap;
171791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
172ff7b7d90SEd Schouten 	struct proc *p;
173ff7b7d90SEd Schouten 	struct thread *td;
174f591779bSSeigo Tanimura 	int retval;
175df8bae1dSRodney W. Grimes 
176ff7b7d90SEd Schouten 	td = curthread;
177ff7b7d90SEd Schouten 	if (TD_IS_IDLETHREAD(td))
178f591779bSSeigo Tanimura 		return (0);
179f591779bSSeigo Tanimura 
1807e99c034SAlex Richardson 	if (td->td_proc == initproc) {
1817e99c034SAlex Richardson 		/* Produce output when we fail to load /sbin/init: */
1827e99c034SAlex Richardson 		va_start(ap, fmt);
1837e99c034SAlex Richardson 		retval = vprintf(fmt, ap);
1847e99c034SAlex Richardson 		va_end(ap);
1857e99c034SAlex Richardson 		return (retval);
1867e99c034SAlex Richardson 	}
1877e99c034SAlex Richardson 
188bc093719SEd Schouten 	sx_slock(&proctree_lock);
189ff7b7d90SEd Schouten 	p = td->td_proc;
190f591779bSSeigo Tanimura 	PROC_LOCK(p);
191f591779bSSeigo Tanimura 	if ((p->p_flag & P_CONTROLT) == 0) {
192f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
1938740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
1948740a711SKonstantin Belousov 		return (0);
195f591779bSSeigo Tanimura 	}
196f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
197791d77e0SPoul-Henning Kamp 	pca.tty = p->p_session->s_ttyp;
198f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
199f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
200329c75a7SRobert Watson 	if (pca.tty == NULL) {
2018740a711SKonstantin Belousov 		sx_sunlock(&proctree_lock);
2028740a711SKonstantin Belousov 		return (0);
203329c75a7SRobert Watson 	}
204791d77e0SPoul-Henning Kamp 	pca.flags = TOTTY;
2055e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
206f591779bSSeigo Tanimura 	va_start(ap, fmt);
207bc093719SEd Schouten 	tty_lock(pca.tty);
2088740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
209f1550d9dSDoug Rabson 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
210bc093719SEd Schouten 	tty_unlock(pca.tty);
211df8bae1dSRodney W. Grimes 	va_end(ap);
21258a24f79SPoul-Henning Kamp 	return (retval);
213df8bae1dSRodney W. Grimes }
214df8bae1dSRodney W. Grimes 
215df8bae1dSRodney W. Grimes /*
21634c916c6SNavdeep Parhar  * tprintf and vtprintf print on the controlling terminal associated with the
21734c916c6SNavdeep Parhar  * given session, possibly to the log as well.
218df8bae1dSRodney W. Grimes  */
219a52585d7SPoul-Henning Kamp void
tprintf(struct proc * p,int pri,const char * fmt,...)220a52585d7SPoul-Henning Kamp tprintf(struct proc *p, int pri, const char *fmt, ...)
221df8bae1dSRodney W. Grimes {
22234c916c6SNavdeep Parhar 	va_list ap;
22334c916c6SNavdeep Parhar 
22434c916c6SNavdeep Parhar 	va_start(ap, fmt);
22534c916c6SNavdeep Parhar 	vtprintf(p, pri, fmt, ap);
22634c916c6SNavdeep Parhar 	va_end(ap);
22734c916c6SNavdeep Parhar }
22834c916c6SNavdeep Parhar 
22934c916c6SNavdeep Parhar void
vtprintf(struct proc * p,int pri,const char * fmt,va_list ap)23034c916c6SNavdeep Parhar vtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
23134c916c6SNavdeep Parhar {
232df8bae1dSRodney W. Grimes 	struct tty *tp = NULL;
233b5a2bad1SJohn Baldwin 	int flags = 0;
234791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
235b5a2bad1SJohn Baldwin 	struct session *sess = NULL;
236df8bae1dSRodney W. Grimes 
237bc093719SEd Schouten 	sx_slock(&proctree_lock);
238e2a09b26SPoul-Henning Kamp 	if (pri != -1)
239a52585d7SPoul-Henning Kamp 		flags |= TOLOG;
240f591779bSSeigo Tanimura 	if (p != NULL) {
241f591779bSSeigo Tanimura 		PROC_LOCK(p);
242f591779bSSeigo Tanimura 		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
243b5a2bad1SJohn Baldwin 			sess = p->p_session;
244bc093719SEd Schouten 			sess_hold(sess);
245f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
246b5a2bad1SJohn Baldwin 			tp = sess->s_ttyp;
247bc093719SEd Schouten 			if (tp != NULL && tty_checkoutq(tp))
248f591779bSSeigo Tanimura 				flags |= TOTTY;
249f591779bSSeigo Tanimura 			else
250f591779bSSeigo Tanimura 				tp = NULL;
251f591779bSSeigo Tanimura 		} else
252f591779bSSeigo Tanimura 			PROC_UNLOCK(p);
253a52585d7SPoul-Henning Kamp 	}
254e2a09b26SPoul-Henning Kamp 	pca.pri = pri;
255791d77e0SPoul-Henning Kamp 	pca.tty = tp;
256791d77e0SPoul-Henning Kamp 	pca.flags = flags;
2575e319c48SKenneth D. Merry 	pca.p_bufr = NULL;
258bc093719SEd Schouten 	if (pca.tty != NULL)
259bc093719SEd Schouten 		tty_lock(pca.tty);
2608740a711SKonstantin Belousov 	sx_sunlock(&proctree_lock);
26174f1af01SPoul-Henning Kamp 	kvprintf(fmt, putchar, &pca, 10, ap);
262bc093719SEd Schouten 	if (pca.tty != NULL)
263bc093719SEd Schouten 		tty_unlock(pca.tty);
264572b4402SPoul-Henning Kamp 	if (sess != NULL)
265bc093719SEd Schouten 		sess_release(sess);
266e2a09b26SPoul-Henning Kamp 	msgbuftrigger = 1;
267df8bae1dSRodney W. Grimes }
268df8bae1dSRodney W. Grimes 
269ae8959ddSBryan Drewery static int
_vprintf(int level,int flags,const char * fmt,va_list ap)270ae8959ddSBryan Drewery _vprintf(int level, int flags, const char *fmt, va_list ap)
271df8bae1dSRodney W. Grimes {
272791d77e0SPoul-Henning Kamp 	struct putchar_arg pca;
273ae8959ddSBryan Drewery 	int retval;
274d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
275d42a4eb5SKenneth D. Merry 	char bufr[PRINTF_BUFR_SIZE];
276d42a4eb5SKenneth D. Merry #endif
277e2a09b26SPoul-Henning Kamp 
278d5d7606cSColin Percival 	TSENTER();
279791d77e0SPoul-Henning Kamp 	pca.tty = NULL;
280e2a09b26SPoul-Henning Kamp 	pca.pri = level;
281ae8959ddSBryan Drewery 	pca.flags = flags;
282d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
283d42a4eb5SKenneth D. Merry 	pca.p_bufr = bufr;
284d42a4eb5SKenneth D. Merry 	pca.p_next = pca.p_bufr;
285d42a4eb5SKenneth D. Merry 	pca.n_bufr = sizeof(bufr);
286d42a4eb5SKenneth D. Merry 	pca.remain = sizeof(bufr);
287d42a4eb5SKenneth D. Merry 	*pca.p_next = '\0';
288d42a4eb5SKenneth D. Merry #else
289ae8959ddSBryan Drewery 	/* Don't buffer console output. */
2903d068827SJohn Birrell 	pca.p_bufr = NULL;
291d42a4eb5SKenneth D. Merry #endif
292e2a09b26SPoul-Henning Kamp 
293ae8959ddSBryan Drewery 	retval = kvprintf(fmt, putchar, &pca, 10, ap);
294e2a09b26SPoul-Henning Kamp 
295d42a4eb5SKenneth D. Merry #ifdef PRINTF_BUFR_SIZE
296d42a4eb5SKenneth D. Merry 	/* Write any buffered console/log output: */
297a264594dSAlexander Motin 	if (*pca.p_bufr != '\0')
298a264594dSAlexander Motin 		prf_putbuf(pca.p_bufr, flags, level);
299d42a4eb5SKenneth D. Merry #endif
300ae8959ddSBryan Drewery 
301d5d7606cSColin Percival 	TSEXIT();
302ae8959ddSBryan Drewery 	return (retval);
303ae8959ddSBryan Drewery }
304ae8959ddSBryan Drewery 
305ae8959ddSBryan Drewery /*
306ae8959ddSBryan Drewery  * Log writes to the log buffer, and guarantees not to sleep (so can be
307ae8959ddSBryan Drewery  * called by interrupt routines).  If there is no process reading the
308ae8959ddSBryan Drewery  * log yet, it writes to the console also.
309ae8959ddSBryan Drewery  */
310ae8959ddSBryan Drewery void
log(int level,const char * fmt,...)311ae8959ddSBryan Drewery log(int level, const char *fmt, ...)
312ae8959ddSBryan Drewery {
313ae8959ddSBryan Drewery 	va_list ap;
314ae8959ddSBryan Drewery 
315ae8959ddSBryan Drewery 	va_start(ap, fmt);
31607713ddeSMark Johnston 	vlog(level, fmt, ap);
317ae8959ddSBryan Drewery 	va_end(ap);
31807713ddeSMark Johnston }
319ae8959ddSBryan Drewery 
32007713ddeSMark Johnston void
vlog(int level,const char * fmt,va_list ap)32107713ddeSMark Johnston vlog(int level, const char *fmt, va_list ap)
32207713ddeSMark Johnston {
32307713ddeSMark Johnston 
32407713ddeSMark Johnston 	(void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
325b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
326df8bae1dSRodney W. Grimes }
327df8bae1dSRodney W. Grimes 
328e2a09b26SPoul-Henning Kamp #define CONSCHUNK 128
329e2a09b26SPoul-Henning Kamp 
330e2a09b26SPoul-Henning Kamp void
log_console(struct uio * uio)331e2a09b26SPoul-Henning Kamp log_console(struct uio *uio)
332df8bae1dSRodney W. Grimes {
333d42a4eb5SKenneth D. Merry 	int c, error, nl;
334e2a09b26SPoul-Henning Kamp 	char *consbuffer;
335e2a09b26SPoul-Henning Kamp 	int pri;
336df8bae1dSRodney W. Grimes 
337dbe620d3SDavid Malone 	if (!log_console_output)
338dbe620d3SDavid Malone 		return;
339dbe620d3SDavid Malone 
340e2a09b26SPoul-Henning Kamp 	pri = LOG_INFO | LOG_CONSOLE;
341552afd9cSPoul-Henning Kamp 	uio = cloneuio(uio);
342552afd9cSPoul-Henning Kamp 	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
343e2a09b26SPoul-Henning Kamp 
3443a4d0c86SEd Schouten 	nl = 0;
345e2a09b26SPoul-Henning Kamp 	while (uio->uio_resid > 0) {
346d42a4eb5SKenneth D. Merry 		c = imin(uio->uio_resid, CONSCHUNK - 1);
347e2a09b26SPoul-Henning Kamp 		error = uiomove(consbuffer, c, uio);
348e2a09b26SPoul-Henning Kamp 		if (error != 0)
3492f9752e9SPoul-Henning Kamp 			break;
350d42a4eb5SKenneth D. Merry 		/* Make sure we're NUL-terminated */
351d42a4eb5SKenneth D. Merry 		consbuffer[c] = '\0';
352d42a4eb5SKenneth D. Merry 		if (consbuffer[c - 1] == '\n')
3533a4d0c86SEd Schouten 			nl = 1;
3543a4d0c86SEd Schouten 		else
3553a4d0c86SEd Schouten 			nl = 0;
356d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
357e2a09b26SPoul-Henning Kamp 	}
358d42a4eb5SKenneth D. Merry 	/*
359d42a4eb5SKenneth D. Merry 	 * The previous behavior in log_console() is preserved when
360d42a4eb5SKenneth D. Merry 	 * log_console_add_linefeed is non-zero.  For that behavior, if an
361d42a4eb5SKenneth D. Merry 	 * individual console write came in that was not terminated with a
362d42a4eb5SKenneth D. Merry 	 * line feed, it would add a line feed.
363d42a4eb5SKenneth D. Merry 	 *
364d42a4eb5SKenneth D. Merry 	 * This results in different data in the message buffer than
365d42a4eb5SKenneth D. Merry 	 * appears on the system console (which doesn't add extra line feed
366d42a4eb5SKenneth D. Merry 	 * characters).
367d42a4eb5SKenneth D. Merry 	 *
368d42a4eb5SKenneth D. Merry 	 * A number of programs and rc scripts write a line feed, or a period
369d42a4eb5SKenneth D. Merry 	 * and a line feed when they have completed their operation.  On
370d42a4eb5SKenneth D. Merry 	 * the console, this looks seamless, but when displayed with
371d42a4eb5SKenneth D. Merry 	 * 'dmesg -a', you wind up with output that looks like this:
372d42a4eb5SKenneth D. Merry 	 *
373d42a4eb5SKenneth D. Merry 	 * Updating motd:
374d42a4eb5SKenneth D. Merry 	 * .
375d42a4eb5SKenneth D. Merry 	 *
376d42a4eb5SKenneth D. Merry 	 * On the console, it looks like this:
377d42a4eb5SKenneth D. Merry 	 * Updating motd:.
378d42a4eb5SKenneth D. Merry 	 *
379d42a4eb5SKenneth D. Merry 	 * We could add logic to detect that situation, or just not insert
380d42a4eb5SKenneth D. Merry 	 * the extra newlines.  Set the kern.log_console_add_linefeed
381d42a4eb5SKenneth D. Merry 	 * sysctl/tunable variable to get the old behavior.
382d42a4eb5SKenneth D. Merry 	 */
383d42a4eb5SKenneth D. Merry 	if (!nl && log_console_add_linefeed) {
384d42a4eb5SKenneth D. Merry 		consbuffer[0] = '\n';
385d42a4eb5SKenneth D. Merry 		consbuffer[1] = '\0';
386d42a4eb5SKenneth D. Merry 		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
3873a4d0c86SEd Schouten 	}
388b80e3b41SPoul-Henning Kamp 	msgbuftrigger = 1;
38961cc4830SAlfredo Mazzinghi 	freeuio(uio);
390552afd9cSPoul-Henning Kamp 	free(consbuffer, M_TEMP);
391df8bae1dSRodney W. Grimes }
392df8bae1dSRodney W. Grimes 
3936ddbf1e2SGary Palmer int
printf(const char * fmt,...)394df8bae1dSRodney W. Grimes printf(const char *fmt, ...)
395df8bae1dSRodney W. Grimes {
396df8bae1dSRodney W. Grimes 	va_list ap;
39765ed8cbdSJustin T. Gibbs 	int retval;
3983d068827SJohn Birrell 
399df8bae1dSRodney W. Grimes 	va_start(ap, fmt);
40091c3cbfeSEd Schouten 	retval = vprintf(fmt, ap);
401df8bae1dSRodney W. Grimes 	va_end(ap);
4023d068827SJohn Birrell 
40358a24f79SPoul-Henning Kamp 	return (retval);
404df8bae1dSRodney W. Grimes }
405df8bae1dSRodney W. Grimes 
406f1550d9dSDoug Rabson int
vprintf(const char * fmt,va_list ap)407791d77e0SPoul-Henning Kamp vprintf(const char *fmt, va_list ap)
408791d77e0SPoul-Henning Kamp {
409f1550d9dSDoug Rabson 	int retval;
4103d068827SJohn Birrell 
411ae8959ddSBryan Drewery 	retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
4123d068827SJohn Birrell 
413879e0604SMateusz Guzik 	if (!KERNEL_PANICKED())
414b80e3b41SPoul-Henning Kamp 		msgbuftrigger = 1;
4153d068827SJohn Birrell 
41658a24f79SPoul-Henning Kamp 	return (retval);
417791d77e0SPoul-Henning Kamp }
418791d77e0SPoul-Henning Kamp 
4193d068827SJohn Birrell static void
prf_putchar(int c,int flags,int pri)420a264594dSAlexander Motin prf_putchar(int c, int flags, int pri)
421a264594dSAlexander Motin {
422a264594dSAlexander Motin 
423c545a7b2SChuck Silvers 	if (flags & TOLOG) {
424a264594dSAlexander Motin 		msglogchar(c, pri);
425c545a7b2SChuck Silvers 		msgbuftrigger = 1;
426c545a7b2SChuck Silvers 	}
427a264594dSAlexander Motin 
428a264594dSAlexander Motin 	if (flags & TOCONS) {
429a264594dSAlexander Motin 		if ((!KERNEL_PANICKED()) && (constty != NULL))
430a264594dSAlexander Motin 			msgbuf_addchar(&consmsgbuf, c);
431a264594dSAlexander Motin 
432a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
433a264594dSAlexander Motin 			cnputc(c);
434a264594dSAlexander Motin 	}
435a264594dSAlexander Motin }
436a264594dSAlexander Motin 
437a264594dSAlexander Motin static void
prf_putbuf(char * bufr,int flags,int pri)438388f3ce6SScott Long prf_putbuf(char *bufr, int flags, int pri)
439388f3ce6SScott Long {
440388f3ce6SScott Long 
441c545a7b2SChuck Silvers 	if (flags & TOLOG) {
442388f3ce6SScott Long 		msglogstr(bufr, pri, /*filter_cr*/1);
443c545a7b2SChuck Silvers 		msgbuftrigger = 1;
444c545a7b2SChuck Silvers 	}
445388f3ce6SScott Long 
446388f3ce6SScott Long 	if (flags & TOCONS) {
447879e0604SMateusz Guzik 		if ((!KERNEL_PANICKED()) && (constty != NULL))
448388f3ce6SScott Long 			msgbuf_addstr(&consmsgbuf, -1,
449388f3ce6SScott Long 			    bufr, /*filter_cr*/ 0);
450388f3ce6SScott Long 
451a264594dSAlexander Motin 		if ((constty == NULL) || always_console_output)
452388f3ce6SScott Long 			cnputs(bufr);
453388f3ce6SScott Long 	}
454388f3ce6SScott Long }
455388f3ce6SScott Long 
456388f3ce6SScott Long static void
putbuf(int c,struct putchar_arg * ap)457d42a4eb5SKenneth D. Merry putbuf(int c, struct putchar_arg *ap)
4583d068827SJohn Birrell {
4593d068827SJohn Birrell 	/* Check if no console output buffer was provided. */
460d42a4eb5SKenneth D. Merry 	if (ap->p_bufr == NULL) {
461a264594dSAlexander Motin 		prf_putchar(c, ap->flags, ap->pri);
462d42a4eb5SKenneth D. Merry 	} else {
4633d068827SJohn Birrell 		/* Buffer the character: */
4643d068827SJohn Birrell 		*ap->p_next++ = c;
4653d068827SJohn Birrell 		ap->remain--;
4663d068827SJohn Birrell 
4673d068827SJohn Birrell 		/* Always leave the buffer zero terminated. */
4683d068827SJohn Birrell 		*ap->p_next = '\0';
4693d068827SJohn Birrell 
4703d068827SJohn Birrell 		/* Check if the buffer needs to be flushed. */
471d42a4eb5SKenneth D. Merry 		if (ap->remain == 2 || c == '\n') {
472388f3ce6SScott Long 			prf_putbuf(ap->p_bufr, ap->flags, ap->pri);
473d42a4eb5SKenneth D. Merry 
4743d068827SJohn Birrell 			ap->p_next = ap->p_bufr;
4753d068827SJohn Birrell 			ap->remain = ap->n_bufr;
4763d068827SJohn Birrell 			*ap->p_next = '\0';
4773d068827SJohn Birrell 		}
478d42a4eb5SKenneth D. Merry 
479d42a4eb5SKenneth D. Merry 		/*
480d42a4eb5SKenneth D. Merry 		 * Since we fill the buffer up one character at a time,
481d42a4eb5SKenneth D. Merry 		 * this should not happen.  We should always catch it when
482d42a4eb5SKenneth D. Merry 		 * ap->remain == 2 (if not sooner due to a newline), flush
483d42a4eb5SKenneth D. Merry 		 * the buffer and move on.  One way this could happen is
484d42a4eb5SKenneth D. Merry 		 * if someone sets PRINTF_BUFR_SIZE to 1 or something
485d42a4eb5SKenneth D. Merry 		 * similarly silly.
486d42a4eb5SKenneth D. Merry 		 */
487d42a4eb5SKenneth D. Merry 		KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
488d42a4eb5SKenneth D. Merry 		    ap->remain));
4893d068827SJohn Birrell 	}
4903d068827SJohn Birrell }
4913d068827SJohn Birrell 
492791d77e0SPoul-Henning Kamp /*
493791d77e0SPoul-Henning Kamp  * Print a character on console or users terminal.  If destination is
494e796e00dSPoul-Henning Kamp  * the console then the last bunch of characters are saved in msgbuf for
495791d77e0SPoul-Henning Kamp  * inspection later.
496791d77e0SPoul-Henning Kamp  */
497791d77e0SPoul-Henning Kamp static void
putchar(int c,void * arg)498791d77e0SPoul-Henning Kamp putchar(int c, void *arg)
499791d77e0SPoul-Henning Kamp {
500791d77e0SPoul-Henning Kamp 	struct putchar_arg *ap = (struct putchar_arg*) arg;
501791d77e0SPoul-Henning Kamp 	struct tty *tp = ap->tty;
5023d068827SJohn Birrell 	int flags = ap->flags;
503d29bf12fSIan Dowse 
504adef9265SIan Dowse 	/* Don't use the tty code after a panic or while in ddb. */
5053d068827SJohn Birrell 	if (kdb_active) {
506d29bf12fSIan Dowse 		if (c != '\0')
507d29bf12fSIan Dowse 			cnputc(c);
50880f1c58bSMarcel Moolenaar 		return;
50980f1c58bSMarcel Moolenaar 	}
51080f1c58bSMarcel Moolenaar 
511879e0604SMateusz Guzik 	if ((flags & TOTTY) && tp != NULL && !KERNEL_PANICKED())
512bc093719SEd Schouten 		tty_putchar(tp, c);
513d42a4eb5SKenneth D. Merry 
51480f1c58bSMarcel Moolenaar 	if ((flags & (TOCONS | TOLOG)) && c != '\0')
515d42a4eb5SKenneth D. Merry 		putbuf(c, ap);
516791d77e0SPoul-Henning Kamp }
517791d77e0SPoul-Henning Kamp 
518791d77e0SPoul-Henning Kamp /*
519791d77e0SPoul-Henning Kamp  * Scaled down version of sprintf(3).
520791d77e0SPoul-Henning Kamp  */
521791d77e0SPoul-Henning Kamp int
sprintf(char * buf,const char * cfmt,...)522791d77e0SPoul-Henning Kamp sprintf(char *buf, const char *cfmt, ...)
523791d77e0SPoul-Henning Kamp {
524791d77e0SPoul-Henning Kamp 	int retval;
525791d77e0SPoul-Henning Kamp 	va_list ap;
526791d77e0SPoul-Henning Kamp 
527791d77e0SPoul-Henning Kamp 	va_start(ap, cfmt);
528791d77e0SPoul-Henning Kamp 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
529fe96d47dSPoul-Henning Kamp 	buf[retval] = '\0';
530791d77e0SPoul-Henning Kamp 	va_end(ap);
53158a24f79SPoul-Henning Kamp 	return (retval);
532791d77e0SPoul-Henning Kamp }
533791d77e0SPoul-Henning Kamp 
534791d77e0SPoul-Henning Kamp /*
53599237364SAndrey A. Chernov  * Scaled down version of vsprintf(3).
53699237364SAndrey A. Chernov  */
53799237364SAndrey A. Chernov int
vsprintf(char * buf,const char * cfmt,va_list ap)53899237364SAndrey A. Chernov vsprintf(char *buf, const char *cfmt, va_list ap)
53999237364SAndrey A. Chernov {
54099237364SAndrey A. Chernov 	int retval;
54199237364SAndrey A. Chernov 
54299237364SAndrey A. Chernov 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
54399237364SAndrey A. Chernov 	buf[retval] = '\0';
54458a24f79SPoul-Henning Kamp 	return (retval);
54599237364SAndrey A. Chernov }
54699237364SAndrey A. Chernov 
54799237364SAndrey A. Chernov /*
5488245f3f5SArchie Cobbs  * Scaled down version of snprintf(3).
5498245f3f5SArchie Cobbs  */
5508245f3f5SArchie Cobbs int
snprintf(char * str,size_t size,const char * format,...)5518245f3f5SArchie Cobbs snprintf(char *str, size_t size, const char *format, ...)
5528245f3f5SArchie Cobbs {
5538245f3f5SArchie Cobbs 	int retval;
5548245f3f5SArchie Cobbs 	va_list ap;
5558245f3f5SArchie Cobbs 
5568245f3f5SArchie Cobbs 	va_start(ap, format);
5578245f3f5SArchie Cobbs 	retval = vsnprintf(str, size, format, ap);
5588245f3f5SArchie Cobbs 	va_end(ap);
5598245f3f5SArchie Cobbs 	return(retval);
5608245f3f5SArchie Cobbs }
5618245f3f5SArchie Cobbs 
5628245f3f5SArchie Cobbs /*
5638245f3f5SArchie Cobbs  * Scaled down version of vsnprintf(3).
5648245f3f5SArchie Cobbs  */
5658245f3f5SArchie Cobbs int
vsnprintf(char * str,size_t size,const char * format,va_list ap)5668245f3f5SArchie Cobbs vsnprintf(char *str, size_t size, const char *format, va_list ap)
5678245f3f5SArchie Cobbs {
5688245f3f5SArchie Cobbs 	struct snprintf_arg info;
5698245f3f5SArchie Cobbs 	int retval;
5708245f3f5SArchie Cobbs 
5718245f3f5SArchie Cobbs 	info.str = str;
5728245f3f5SArchie Cobbs 	info.remain = size;
5738245f3f5SArchie Cobbs 	retval = kvprintf(format, snprintf_func, &info, 10, ap);
5748245f3f5SArchie Cobbs 	if (info.remain >= 1)
5758245f3f5SArchie Cobbs 		*info.str++ = '\0';
57658a24f79SPoul-Henning Kamp 	return (retval);
5778245f3f5SArchie Cobbs }
5788245f3f5SArchie Cobbs 
5798751a8c7SPoul-Henning Kamp /*
5808751a8c7SPoul-Henning Kamp  * Kernel version which takes radix argument vsnprintf(3).
5818751a8c7SPoul-Henning Kamp  */
5828751a8c7SPoul-Henning Kamp int
vsnrprintf(char * str,size_t size,int radix,const char * format,va_list ap)5838751a8c7SPoul-Henning Kamp vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
5848751a8c7SPoul-Henning Kamp {
5858751a8c7SPoul-Henning Kamp 	struct snprintf_arg info;
5868751a8c7SPoul-Henning Kamp 	int retval;
5878751a8c7SPoul-Henning Kamp 
5888751a8c7SPoul-Henning Kamp 	info.str = str;
5898751a8c7SPoul-Henning Kamp 	info.remain = size;
5908751a8c7SPoul-Henning Kamp 	retval = kvprintf(format, snprintf_func, &info, radix, ap);
5918751a8c7SPoul-Henning Kamp 	if (info.remain >= 1)
5928751a8c7SPoul-Henning Kamp 		*info.str++ = '\0';
5938751a8c7SPoul-Henning Kamp 	return (retval);
5948751a8c7SPoul-Henning Kamp }
5958751a8c7SPoul-Henning Kamp 
5968245f3f5SArchie Cobbs static void
snprintf_func(int ch,void * arg)5978245f3f5SArchie Cobbs snprintf_func(int ch, void *arg)
5988245f3f5SArchie Cobbs {
5998245f3f5SArchie Cobbs 	struct snprintf_arg *const info = arg;
6008245f3f5SArchie Cobbs 
6018245f3f5SArchie Cobbs 	if (info->remain >= 2) {
6028245f3f5SArchie Cobbs 		*info->str++ = ch;
6038245f3f5SArchie Cobbs 		info->remain--;
6048245f3f5SArchie Cobbs 	}
6058245f3f5SArchie Cobbs }
6068245f3f5SArchie Cobbs 
6078245f3f5SArchie Cobbs /*
60882941964SPeter Wemm  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
60905292ba2SArchie Cobbs  * order; return an optional length and a pointer to the last character
61005292ba2SArchie Cobbs  * written in the buffer (i.e., the first character of the string).
61105292ba2SArchie Cobbs  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
612791d77e0SPoul-Henning Kamp  */
613791d77e0SPoul-Henning Kamp static char *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)6140d84d9ebSJung-uk Kim ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
61505292ba2SArchie Cobbs {
6160d84d9ebSJung-uk Kim 	char *p, c;
617791d77e0SPoul-Henning Kamp 
61805292ba2SArchie Cobbs 	p = nbuf;
619ad4f8dbdSArchie Cobbs 	*p = '\0';
620791d77e0SPoul-Henning Kamp 	do {
6210d84d9ebSJung-uk Kim 		c = hex2ascii(num % base);
6220d84d9ebSJung-uk Kim 		*++p = upper ? toupper(c) : c;
6233b1f7e7dSDag-Erling Smørgrav 	} while (num /= base);
6247d921a01SPeter Wemm 	if (lenp)
6257d921a01SPeter Wemm 		*lenp = p - nbuf;
6267d921a01SPeter Wemm 	return (p);
6277d921a01SPeter Wemm }
628791d77e0SPoul-Henning Kamp 
629df8bae1dSRodney W. Grimes /*
630df8bae1dSRodney W. Grimes  * Scaled down version of printf(3).
631df8bae1dSRodney W. Grimes  *
632df8bae1dSRodney W. Grimes  * Two additional formats:
633df8bae1dSRodney W. Grimes  *
634df8bae1dSRodney W. Grimes  * The format %b is supported to decode error registers.
635df8bae1dSRodney W. Grimes  * Its usage is:
636df8bae1dSRodney W. Grimes  *
637df8bae1dSRodney W. Grimes  *	printf("reg=%b\n", regval, "<base><arg>*");
638df8bae1dSRodney W. Grimes  *
639df8bae1dSRodney W. Grimes  * where <base> is the output base expressed as a control character, e.g.
640df8bae1dSRodney W. Grimes  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
641df8bae1dSRodney W. Grimes  * the first of which gives the bit number to be inspected (origin 1), and
642df8bae1dSRodney W. Grimes  * the next characters (up to a control character, i.e. a character <= 32),
643df8bae1dSRodney W. Grimes  * give the name of the register.  Thus:
644df8bae1dSRodney W. Grimes  *
645c5f282daSAlexey Dokuchaev  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
646df8bae1dSRodney W. Grimes  *
647df8bae1dSRodney W. Grimes  * would produce output:
648df8bae1dSRodney W. Grimes  *
649df8bae1dSRodney W. Grimes  *	reg=3<BITTWO,BITONE>
650df8bae1dSRodney W. Grimes  *
651120f0783SPoul-Henning Kamp  * XXX:  %D  -- Hexdump, takes pointer and separator string:
652120f0783SPoul-Henning Kamp  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
653120f0783SPoul-Henning Kamp  *		("%*D", len, ptr, " " -> XX XX XX XX ...
654df8bae1dSRodney W. Grimes  */
655791d77e0SPoul-Henning Kamp int
kvprintf(char const * fmt,void (* func)(int,void *),void * arg,int radix,va_list ap)656791d77e0SPoul-Henning Kamp kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
657df8bae1dSRodney W. Grimes {
658791d77e0SPoul-Henning Kamp #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
659ad4f8dbdSArchie Cobbs 	char nbuf[MAXNBUF];
6603b1f7e7dSDag-Erling Smørgrav 	char *d;
6613b1f7e7dSDag-Erling Smørgrav 	const char *p, *percent, *q;
662120f0783SPoul-Henning Kamp 	u_char *up;
663*07d90ee0SSebastian Huber 	int ch, n, sign;
6643b1f7e7dSDag-Erling Smørgrav 	uintmax_t num;
665*07d90ee0SSebastian Huber 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, dot;
66632869e71SNate Lawson 	int cflag, hflag, jflag, tflag, zflag;
667808a9c86SRyan Libby 	int bconv, dwidth, upper;
668df8bae1dSRodney W. Grimes 	char padc;
6691e7d2c47SPoul-Henning Kamp 	int stop = 0, retval = 0;
670791d77e0SPoul-Henning Kamp 
6713b1f7e7dSDag-Erling Smørgrav 	num = 0;
672b2037136SMatt Macy 	q = NULL;
673fe96d47dSPoul-Henning Kamp 	if (!func)
674791d77e0SPoul-Henning Kamp 		d = (char *) arg;
675791d77e0SPoul-Henning Kamp 	else
676fe96d47dSPoul-Henning Kamp 		d = NULL;
6778f5067baSDavid Greenman 
6788f5067baSDavid Greenman 	if (fmt == NULL)
6792336b9d7SBruce Evans 		fmt = "(fmt null)\n";
680b4b2f81eSPoul-Henning Kamp 
681120f0783SPoul-Henning Kamp 	if (radix < 2 || radix > 36)
682b4b2f81eSPoul-Henning Kamp 		radix = 10;
683b4b2f81eSPoul-Henning Kamp 
684df8bae1dSRodney W. Grimes 	for (;;) {
685df8bae1dSRodney W. Grimes 		padc = ' ';
686df8bae1dSRodney W. Grimes 		width = 0;
6871e7d2c47SPoul-Henning Kamp 		while ((ch = (u_char)*fmt++) != '%' || stop) {
688df8bae1dSRodney W. Grimes 			if (ch == '\0')
68958a24f79SPoul-Henning Kamp 				return (retval);
690791d77e0SPoul-Henning Kamp 			PCHAR(ch);
691df8bae1dSRodney W. Grimes 		}
6923b1f7e7dSDag-Erling Smørgrav 		percent = fmt - 1;
693*07d90ee0SSebastian Huber 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0;
694808a9c86SRyan Libby 		sign = 0; dot = 0; bconv = 0; dwidth = 0; upper = 0;
69532869e71SNate Lawson 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
696e0c95ed9SBruce Evans reswitch:	switch (ch = (u_char)*fmt++) {
6974830092aSPoul-Henning Kamp 		case '.':
6984830092aSPoul-Henning Kamp 			dot = 1;
6994830092aSPoul-Henning Kamp 			goto reswitch;
700791d77e0SPoul-Henning Kamp 		case '#':
701791d77e0SPoul-Henning Kamp 			sharpflag = 1;
702791d77e0SPoul-Henning Kamp 			goto reswitch;
703791d77e0SPoul-Henning Kamp 		case '+':
704*07d90ee0SSebastian Huber 			sign = '+';
705791d77e0SPoul-Henning Kamp 			goto reswitch;
706791d77e0SPoul-Henning Kamp 		case '-':
707791d77e0SPoul-Henning Kamp 			ladjust = 1;
708791d77e0SPoul-Henning Kamp 			goto reswitch;
709791d77e0SPoul-Henning Kamp 		case '%':
710791d77e0SPoul-Henning Kamp 			PCHAR(ch);
711791d77e0SPoul-Henning Kamp 			break;
712791d77e0SPoul-Henning Kamp 		case '*':
713ed71c342SPoul-Henning Kamp 			if (!dot) {
714791d77e0SPoul-Henning Kamp 				width = va_arg(ap, int);
715791d77e0SPoul-Henning Kamp 				if (width < 0) {
716791d77e0SPoul-Henning Kamp 					ladjust = !ladjust;
717791d77e0SPoul-Henning Kamp 					width = -width;
718791d77e0SPoul-Henning Kamp 				}
719ed71c342SPoul-Henning Kamp 			} else {
720ed71c342SPoul-Henning Kamp 				dwidth = va_arg(ap, int);
721ed71c342SPoul-Henning Kamp 			}
722791d77e0SPoul-Henning Kamp 			goto reswitch;
723df8bae1dSRodney W. Grimes 		case '0':
7244f20e4b1SPoul-Henning Kamp 			if (!dot) {
725df8bae1dSRodney W. Grimes 				padc = '0';
726df8bae1dSRodney W. Grimes 				goto reswitch;
7274f20e4b1SPoul-Henning Kamp 			}
7289295517aSMark Johnston 			/* FALLTHROUGH */
729df8bae1dSRodney W. Grimes 		case '1': case '2': case '3': case '4':
730df8bae1dSRodney W. Grimes 		case '5': case '6': case '7': case '8': case '9':
7314f20e4b1SPoul-Henning Kamp 				for (n = 0;; ++fmt) {
7324f20e4b1SPoul-Henning Kamp 					n = n * 10 + ch - '0';
733df8bae1dSRodney W. Grimes 					ch = *fmt;
734df8bae1dSRodney W. Grimes 					if (ch < '0' || ch > '9')
735df8bae1dSRodney W. Grimes 						break;
736df8bae1dSRodney W. Grimes 				}
7374f20e4b1SPoul-Henning Kamp 			if (dot)
7384f20e4b1SPoul-Henning Kamp 				dwidth = n;
7394f20e4b1SPoul-Henning Kamp 			else
7404f20e4b1SPoul-Henning Kamp 				width = n;
741df8bae1dSRodney W. Grimes 			goto reswitch;
742df8bae1dSRodney W. Grimes 		case 'b':
743808a9c86SRyan Libby 			ladjust = 1;
744808a9c86SRyan Libby 			bconv = 1;
745808a9c86SRyan Libby 			goto handle_nosign;
746df8bae1dSRodney W. Grimes 		case 'c':
747dd6ea7f7SConrad Meyer 			width -= 1;
748dd6ea7f7SConrad Meyer 
749dd6ea7f7SConrad Meyer 			if (!ladjust && width > 0)
750dd6ea7f7SConrad Meyer 				while (width--)
751dd6ea7f7SConrad Meyer 					PCHAR(padc);
752791d77e0SPoul-Henning Kamp 			PCHAR(va_arg(ap, int));
753dd6ea7f7SConrad Meyer 			if (ladjust && width > 0)
754dd6ea7f7SConrad Meyer 				while (width--)
755dd6ea7f7SConrad Meyer 					PCHAR(padc);
756df8bae1dSRodney W. Grimes 			break;
757120f0783SPoul-Henning Kamp 		case 'D':
758120f0783SPoul-Henning Kamp 			up = va_arg(ap, u_char *);
759120f0783SPoul-Henning Kamp 			p = va_arg(ap, char *);
760120f0783SPoul-Henning Kamp 			if (!width)
761120f0783SPoul-Henning Kamp 				width = 16;
762120f0783SPoul-Henning Kamp 			while(width--) {
763120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up >> 4));
764120f0783SPoul-Henning Kamp 				PCHAR(hex2ascii(*up & 0x0f));
765120f0783SPoul-Henning Kamp 				up++;
766120f0783SPoul-Henning Kamp 				if (width)
767120f0783SPoul-Henning Kamp 					for (q=p;*q;q++)
768120f0783SPoul-Henning Kamp 						PCHAR(*q);
769120f0783SPoul-Henning Kamp 			}
770120f0783SPoul-Henning Kamp 			break;
771df8bae1dSRodney W. Grimes 		case 'd':
772e0b74464SWarner Losh 		case 'i':
773df8bae1dSRodney W. Grimes 			base = 10;
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;
826*07d90ee0SSebastian Huber 			if (sign) {
827*07d90ee0SSebastian Huber 				sign = 0;
8283b1f7e7dSDag-Erling Smørgrav 				goto handle_sign;
829*07d90ee0SSebastian Huber 			}
8303b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
831791d77e0SPoul-Henning Kamp 		case 's':
832791d77e0SPoul-Henning Kamp 			p = va_arg(ap, char *);
833791d77e0SPoul-Henning Kamp 			if (p == NULL)
834791d77e0SPoul-Henning Kamp 				p = "(null)";
8354830092aSPoul-Henning Kamp 			if (!dot)
8364830092aSPoul-Henning Kamp 				n = strlen (p);
8374830092aSPoul-Henning Kamp 			else
8384f20e4b1SPoul-Henning Kamp 				for (n = 0; n < dwidth && p[n]; n++)
8394830092aSPoul-Henning Kamp 					continue;
8404f20e4b1SPoul-Henning Kamp 
8414830092aSPoul-Henning Kamp 			width -= n;
8424f20e4b1SPoul-Henning Kamp 
843791d77e0SPoul-Henning Kamp 			if (!ladjust && width > 0)
844791d77e0SPoul-Henning Kamp 				while (width--)
845791d77e0SPoul-Henning Kamp 					PCHAR(padc);
8464830092aSPoul-Henning Kamp 			while (n--)
847791d77e0SPoul-Henning Kamp 				PCHAR(*p++);
848791d77e0SPoul-Henning Kamp 			if (ladjust && width > 0)
849791d77e0SPoul-Henning Kamp 				while (width--)
850791d77e0SPoul-Henning Kamp 					PCHAR(padc);
851791d77e0SPoul-Henning Kamp 			break;
8522bb95458SMaxime Henrion 		case 't':
8532bb95458SMaxime Henrion 			tflag = 1;
8542bb95458SMaxime Henrion 			goto reswitch;
855f53dbe97SBruce Evans 		case 'u':
856f53dbe97SBruce Evans 			base = 10;
8573b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
858aa998012SMike Smith 		case 'X':
8590d84d9ebSJung-uk Kim 			upper = 1;
860679e4cdaSMarius Strobl 			/* FALLTHROUGH */
8610d84d9ebSJung-uk Kim 		case 'x':
862df8bae1dSRodney W. Grimes 			base = 16;
8633b1f7e7dSDag-Erling Smørgrav 			goto handle_nosign;
8644578a2e6SMaxime Henrion 		case 'y':
865e0c38587SBruce Evans 			base = 16;
8663b1f7e7dSDag-Erling Smørgrav 			goto handle_sign;
8674578a2e6SMaxime Henrion 		case 'z':
8684578a2e6SMaxime Henrion 			zflag = 1;
8694578a2e6SMaxime Henrion 			goto reswitch;
8703b1f7e7dSDag-Erling Smørgrav handle_nosign:
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)
906fc3e5334SSebastian Huber 				num = (signed char)va_arg(ap, int);
9073b1f7e7dSDag-Erling Smørgrav 			else
9083b1f7e7dSDag-Erling Smørgrav 				num = va_arg(ap, int);
909*07d90ee0SSebastian Huber 			if ((intmax_t)num < 0) {
910*07d90ee0SSebastian Huber 				sign = '-';
9113b1f7e7dSDag-Erling Smørgrav 				num = -(intmax_t)num;
9127d921a01SPeter Wemm 			}
913*07d90ee0SSebastian Huber number:
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 			}
922*07d90ee0SSebastian Huber 			if (sign)
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(' ');
932*07d90ee0SSebastian Huber 			if (sign)
933*07d90ee0SSebastian Huber 				PCHAR(sign);
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
msglogchar(int c,int pri)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
msglogstr(char * str,int pri,int filter_cr)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
msgbufinit(void * ptr,int size)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 
10409d6ae1e3SColin Percival 	TSENTER();
1041cca8f980SIan Dowse 	size -= sizeof(*msgbufp);
1042e796e00dSPoul-Henning Kamp 	cp = (char *)ptr;
1043170bc291SKyle Evans 	print_boot_tag = !msgbufmapped;
10442a4650ccSKyle Evans 	/* Attempt to fetch kern.boot_tag tunable on first mapping */
10452a4650ccSKyle Evans 	if (!msgbufmapped)
10462a4650ccSKyle Evans 		TUNABLE_STR_FETCH("kern.boot_tag", current_boot_tag,
1047240fcda1SKyle Evans 		    sizeof(current_boot_tag));
1048cca8f980SIan Dowse 	msgbufp = (struct msgbuf *)(cp + size);
10494784a469SIan Dowse 	msgbuf_reinit(msgbufp, cp, size);
1050eb9d435aSJonathan Lemon 	if (msgbufmapped && oldp != msgbufp)
10514784a469SIan Dowse 		msgbuf_copy(oldp, msgbufp);
105221aa6e83SKyle Evans 	msgbufmapped = true;
105345625675SKyle Evans 	if (print_boot_tag && *current_boot_tag != '\0')
1054170bc291SKyle Evans 		printf("%s\n", current_boot_tag);
1055eb9d435aSJonathan Lemon 	oldp = msgbufp;
10569d6ae1e3SColin Percival 	TSEXIT();
1057e796e00dSPoul-Henning Kamp }
1058e796e00dSPoul-Henning Kamp 
1059948d3d94SThomas Moestl /* Sysctls for accessing/clearing the msgbuf */
1060948d3d94SThomas Moestl static int
sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)1061948d3d94SThomas Moestl sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
1062948d3d94SThomas Moestl {
1063c999e348SGleb Smirnoff 	char buf[128], *bp;
10644784a469SIan Dowse 	u_int seq;
10654784a469SIan Dowse 	int error, len;
1066c999e348SGleb Smirnoff 	bool wrap;
1067948d3d94SThomas Moestl 
1068acd3428bSRobert Watson 	error = priv_check(req->td, PRIV_MSGBUF);
10696f3933faSRobert Watson 	if (error)
10706f3933faSRobert Watson 		return (error);
10716f3933faSRobert Watson 
10724784a469SIan Dowse 	/* Read the whole buffer, one chunk at a time. */
1073ca1d2f65SEd Schouten 	mtx_lock(&msgbuf_lock);
10744784a469SIan Dowse 	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
1075c999e348SGleb Smirnoff 	wrap = (seq != 0);
1076ca1d2f65SEd Schouten 	for (;;) {
1077ca1d2f65SEd Schouten 		len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
1078ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
1079ca1d2f65SEd Schouten 		if (len == 0)
1080e5197e3aSIan Lepore 			return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
1081c999e348SGleb Smirnoff 		if (wrap) {
1082c999e348SGleb Smirnoff 			/* Skip the first line, as it is probably incomplete. */
1083c999e348SGleb Smirnoff 			bp = memchr(buf, '\n', len);
1084c999e348SGleb Smirnoff 			if (bp == NULL) {
1085c999e348SGleb Smirnoff 				mtx_lock(&msgbuf_lock);
1086c999e348SGleb Smirnoff 				continue;
1087c999e348SGleb Smirnoff 			}
1088c999e348SGleb Smirnoff 			wrap = false;
1089c999e348SGleb Smirnoff 			bp++;
1090c999e348SGleb Smirnoff 			len -= bp - buf;
1091c999e348SGleb Smirnoff 			if (len == 0) {
1092c999e348SGleb Smirnoff 				mtx_lock(&msgbuf_lock);
1093c999e348SGleb Smirnoff 				continue;
1094c999e348SGleb Smirnoff 			}
1095c999e348SGleb Smirnoff 		} else
1096c999e348SGleb Smirnoff 			bp = buf;
1097c999e348SGleb Smirnoff 		error = sysctl_handle_opaque(oidp, bp, len, req);
1098948d3d94SThomas Moestl 		if (error)
1099948d3d94SThomas Moestl 			return (error);
1100ca1d2f65SEd Schouten 
1101ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
1102948d3d94SThomas Moestl 	}
1103948d3d94SThomas Moestl }
1104948d3d94SThomas Moestl 
1105ca1d2f65SEd Schouten SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
1106ca1d2f65SEd Schouten     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
11074592c621SWarner Losh     NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
1108948d3d94SThomas Moestl 
11094784a469SIan Dowse static int msgbuf_clearflag;
1110948d3d94SThomas Moestl 
1111948d3d94SThomas Moestl static int
sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)1112948d3d94SThomas Moestl sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
1113948d3d94SThomas Moestl {
1114948d3d94SThomas Moestl 	int error;
1115948d3d94SThomas Moestl 	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1116948d3d94SThomas Moestl 	if (!error && req->newptr) {
1117ca1d2f65SEd Schouten 		mtx_lock(&msgbuf_lock);
11184784a469SIan Dowse 		msgbuf_clear(msgbufp);
1119ca1d2f65SEd Schouten 		mtx_unlock(&msgbuf_lock);
11204784a469SIan Dowse 		msgbuf_clearflag = 0;
1121948d3d94SThomas Moestl 	}
1122948d3d94SThomas Moestl 	return (error);
1123948d3d94SThomas Moestl }
1124948d3d94SThomas Moestl 
1125948d3d94SThomas Moestl SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
1126ca1d2f65SEd Schouten     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE,
1127ca1d2f65SEd Schouten     &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I",
1128ca1d2f65SEd Schouten     "Clear kernel message buffer");
1129948d3d94SThomas Moestl 
1130e796e00dSPoul-Henning Kamp #ifdef DDB
1131e796e00dSPoul-Henning Kamp 
DB_SHOW_COMMAND_FLAGS(msgbuf,db_show_msgbuf,DB_CMD_MEMSAFE)1132c84c5e00SMitchell Horne DB_SHOW_COMMAND_FLAGS(msgbuf, db_show_msgbuf, DB_CMD_MEMSAFE)
1133e796e00dSPoul-Henning Kamp {
113419e9205aSJohn Baldwin 	int i, j;
1135e796e00dSPoul-Henning Kamp 
1136e796e00dSPoul-Henning Kamp 	if (!msgbufmapped) {
1137e796e00dSPoul-Henning Kamp 		db_printf("msgbuf not mapped yet\n");
1138e796e00dSPoul-Henning Kamp 		return;
1139e796e00dSPoul-Henning Kamp 	}
1140e796e00dSPoul-Henning Kamp 	db_printf("msgbufp = %p\n", msgbufp);
11414784a469SIan Dowse 	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
11424784a469SIan Dowse 	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
11434784a469SIan Dowse 	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
114419e9205aSJohn Baldwin 	for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) {
11454784a469SIan Dowse 		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
1146e796e00dSPoul-Henning Kamp 		db_printf("%c", msgbufp->msg_ptr[j]);
1147e796e00dSPoul-Henning Kamp 	}
1148e796e00dSPoul-Henning Kamp 	db_printf("\n");
1149e796e00dSPoul-Henning Kamp }
1150e796e00dSPoul-Henning Kamp 
1151e796e00dSPoul-Henning Kamp #endif /* DDB */
115277411499SScott Long 
115377411499SScott Long void
hexdump(const void * ptr,int length,const char * hdr,int flags)115430a1695bSPoul-Henning Kamp hexdump(const void *ptr, int length, const char *hdr, int flags)
115577411499SScott Long {
115677411499SScott Long 	int i, j, k;
115777411499SScott Long 	int cols;
115830a1695bSPoul-Henning Kamp 	const unsigned char *cp;
115977411499SScott Long 	char delim;
116077411499SScott Long 
116177411499SScott Long 	if ((flags & HD_DELIM_MASK) != 0)
116277411499SScott Long 		delim = (flags & HD_DELIM_MASK) >> 8;
116377411499SScott Long 	else
116477411499SScott Long 		delim = ' ';
116577411499SScott Long 
116677411499SScott Long 	if ((flags & HD_COLUMN_MASK) != 0)
116777411499SScott Long 		cols = flags & HD_COLUMN_MASK;
116877411499SScott Long 	else
116977411499SScott Long 		cols = 16;
117077411499SScott Long 
117177411499SScott Long 	cp = ptr;
117277411499SScott Long 	for (i = 0; i < length; i+= cols) {
117377411499SScott Long 		if (hdr != NULL)
117477411499SScott Long 			printf("%s", hdr);
117577411499SScott Long 
117677411499SScott Long 		if ((flags & HD_OMIT_COUNT) == 0)
117777411499SScott Long 			printf("%04x  ", i);
117877411499SScott Long 
117977411499SScott Long 		if ((flags & HD_OMIT_HEX) == 0) {
118077411499SScott Long 			for (j = 0; j < cols; j++) {
118177411499SScott Long 				k = i + j;
118277411499SScott Long 				if (k < length)
118377411499SScott Long 					printf("%c%02x", delim, cp[k]);
118477411499SScott Long 				else
118577411499SScott Long 					printf("   ");
118677411499SScott Long 			}
118777411499SScott Long 		}
118877411499SScott Long 
118977411499SScott Long 		if ((flags & HD_OMIT_CHARS) == 0) {
119077411499SScott Long 			printf("  |");
119177411499SScott Long 			for (j = 0; j < cols; j++) {
119277411499SScott Long 				k = i + j;
119377411499SScott Long 				if (k >= length)
119477411499SScott Long 					printf(" ");
119577411499SScott Long 				else if (cp[k] >= ' ' && cp[k] <= '~')
119677411499SScott Long 					printf("%c", cp[k]);
119777411499SScott Long 				else
119877411499SScott Long 					printf(".");
119977411499SScott Long 			}
12006ec6fb9bSScott Long 			printf("|");
120177411499SScott Long 		}
12026ec6fb9bSScott Long 		printf("\n");
120377411499SScott Long 	}
120477411499SScott Long }
12055672fac9SKenneth D. Merry #endif /* _KERNEL */
12065672fac9SKenneth D. Merry 
12075672fac9SKenneth D. Merry void
sbuf_hexdump(struct sbuf * sb,const void * ptr,int length,const char * hdr,int flags)12085672fac9SKenneth D. Merry sbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
12095672fac9SKenneth D. Merry 	     int flags)
12105672fac9SKenneth D. Merry {
12115672fac9SKenneth D. Merry 	int i, j, k;
12125672fac9SKenneth D. Merry 	int cols;
12135672fac9SKenneth D. Merry 	const unsigned char *cp;
12145672fac9SKenneth D. Merry 	char delim;
12155672fac9SKenneth D. Merry 
12165672fac9SKenneth D. Merry 	if ((flags & HD_DELIM_MASK) != 0)
12175672fac9SKenneth D. Merry 		delim = (flags & HD_DELIM_MASK) >> 8;
12185672fac9SKenneth D. Merry 	else
12195672fac9SKenneth D. Merry 		delim = ' ';
12205672fac9SKenneth D. Merry 
12215672fac9SKenneth D. Merry 	if ((flags & HD_COLUMN_MASK) != 0)
12225672fac9SKenneth D. Merry 		cols = flags & HD_COLUMN_MASK;
12235672fac9SKenneth D. Merry 	else
12245672fac9SKenneth D. Merry 		cols = 16;
12255672fac9SKenneth D. Merry 
12265672fac9SKenneth D. Merry 	cp = ptr;
12275672fac9SKenneth D. Merry 	for (i = 0; i < length; i+= cols) {
12285672fac9SKenneth D. Merry 		if (hdr != NULL)
12295672fac9SKenneth D. Merry 			sbuf_printf(sb, "%s", hdr);
12305672fac9SKenneth D. Merry 
12315672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_COUNT) == 0)
12325672fac9SKenneth D. Merry 			sbuf_printf(sb, "%04x  ", i);
12335672fac9SKenneth D. Merry 
12345672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_HEX) == 0) {
12355672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12365672fac9SKenneth D. Merry 				k = i + j;
12375672fac9SKenneth D. Merry 				if (k < length)
12385672fac9SKenneth D. Merry 					sbuf_printf(sb, "%c%02x", delim, cp[k]);
12395672fac9SKenneth D. Merry 				else
12400a713948SAlexander Motin 					sbuf_cat(sb, "   ");
12415672fac9SKenneth D. Merry 			}
12425672fac9SKenneth D. Merry 		}
12435672fac9SKenneth D. Merry 
12445672fac9SKenneth D. Merry 		if ((flags & HD_OMIT_CHARS) == 0) {
12450a713948SAlexander Motin 			sbuf_cat(sb, "  |");
12465672fac9SKenneth D. Merry 			for (j = 0; j < cols; j++) {
12475672fac9SKenneth D. Merry 				k = i + j;
12485672fac9SKenneth D. Merry 				if (k >= length)
12490a713948SAlexander Motin 					sbuf_putc(sb, ' ');
12505672fac9SKenneth D. Merry 				else if (cp[k] >= ' ' && cp[k] <= '~')
12510a713948SAlexander Motin 					sbuf_putc(sb, cp[k]);
12525672fac9SKenneth D. Merry 				else
12530a713948SAlexander Motin 					sbuf_putc(sb, '.');
12545672fac9SKenneth D. Merry 			}
12550a713948SAlexander Motin 			sbuf_putc(sb, '|');
12565672fac9SKenneth D. Merry 		}
12570a713948SAlexander Motin 		sbuf_putc(sb, '\n');
12585672fac9SKenneth D. Merry 	}
12595672fac9SKenneth D. Merry }
12605672fac9SKenneth D. Merry 
1261492fe1b7SKonstantin Belousov #ifdef _KERNEL
12629837947bSKonstantin Belousov void
counted_warning(unsigned * counter,const char * msg)12639837947bSKonstantin Belousov counted_warning(unsigned *counter, const char *msg)
12649837947bSKonstantin Belousov {
12659837947bSKonstantin Belousov 	struct thread *td;
12669837947bSKonstantin Belousov 	unsigned c;
12679837947bSKonstantin Belousov 
12689837947bSKonstantin Belousov 	for (;;) {
12699837947bSKonstantin Belousov 		c = *counter;
12709837947bSKonstantin Belousov 		if (c == 0)
12719837947bSKonstantin Belousov 			break;
12729837947bSKonstantin Belousov 		if (atomic_cmpset_int(counter, c, c - 1)) {
12739837947bSKonstantin Belousov 			td = curthread;
12749837947bSKonstantin Belousov 			log(LOG_INFO, "pid %d (%s) %s%s\n",
12759837947bSKonstantin Belousov 			    td->td_proc->p_pid, td->td_name, msg,
12769837947bSKonstantin Belousov 			    c > 1 ? "" : " - not logging anymore");
12779837947bSKonstantin Belousov 			break;
12789837947bSKonstantin Belousov 		}
12799837947bSKonstantin Belousov 	}
12809837947bSKonstantin Belousov }
1281492fe1b7SKonstantin Belousov #endif
1282388f3ce6SScott Long 
1283388f3ce6SScott Long #ifdef _KERNEL
1284388f3ce6SScott Long void
sbuf_putbuf(struct sbuf * sb)1285388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1286388f3ce6SScott Long {
1287388f3ce6SScott Long 
1288388f3ce6SScott Long 	prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1);
1289388f3ce6SScott Long }
1290388f3ce6SScott Long #else
1291388f3ce6SScott Long void
sbuf_putbuf(struct sbuf * sb)1292388f3ce6SScott Long sbuf_putbuf(struct sbuf *sb)
1293388f3ce6SScott Long {
1294388f3ce6SScott Long 
1295388f3ce6SScott Long 	printf("%s", sbuf_data(sb));
1296388f3ce6SScott Long }
1297388f3ce6SScott Long #endif
12987d7db529SConrad Meyer 
12997d7db529SConrad Meyer int
sbuf_printf_drain(void * arg,const char * data,int len)13007d7db529SConrad Meyer sbuf_printf_drain(void *arg, const char *data, int len)
13017d7db529SConrad Meyer {
13027d7db529SConrad Meyer 	size_t *retvalptr;
13037d7db529SConrad Meyer 	int r;
13047d7db529SConrad Meyer #ifdef _KERNEL
13057d7db529SConrad Meyer 	char *dataptr;
13067d7db529SConrad Meyer 	char oldchr;
13077d7db529SConrad Meyer 
13087d7db529SConrad Meyer 	/*
13097d7db529SConrad Meyer 	 * This is allowed as an extra byte is always resvered for
13107d7db529SConrad Meyer 	 * terminating NUL byte.  Save and restore the byte because
13117d7db529SConrad Meyer 	 * we might be flushing a record, and there may be valid
13127d7db529SConrad Meyer 	 * data after the buffer.
13137d7db529SConrad Meyer 	 */
13147d7db529SConrad Meyer 	oldchr = data[len];
13157d7db529SConrad Meyer 	dataptr = __DECONST(char *, data);
13167d7db529SConrad Meyer 	dataptr[len] = '\0';
13177d7db529SConrad Meyer 
13187d7db529SConrad Meyer 	prf_putbuf(dataptr, TOLOG | TOCONS, -1);
13197d7db529SConrad Meyer 	r = len;
13207d7db529SConrad Meyer 
13217d7db529SConrad Meyer 	dataptr[len] = oldchr;
13227d7db529SConrad Meyer 
13237d7db529SConrad Meyer #else /* !_KERNEL */
13247d7db529SConrad Meyer 
13257d7db529SConrad Meyer 	r = printf("%.*s", len, data);
13267d7db529SConrad Meyer 	if (r < 0)
13277d7db529SConrad Meyer 		return (-errno);
13287d7db529SConrad Meyer 
13297d7db529SConrad Meyer #endif
13307d7db529SConrad Meyer 
13317d7db529SConrad Meyer 	retvalptr = arg;
13327d7db529SConrad Meyer 	if (retvalptr != NULL)
13337d7db529SConrad Meyer 		*retvalptr += r;
13347d7db529SConrad Meyer 
13357d7db529SConrad Meyer 	return (r);
13367d7db529SConrad Meyer }
1337