11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1986, 1988, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
341541Srgrimes *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
351541Srgrimes */
361541Srgrimes
37116182Sobrien#include <sys/cdefs.h>
38116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/subr_prf.c 339446 2018-10-20 16:20:36Z jamie $");
39116182Sobrien
40284192Sken#ifdef _KERNEL
41108678Sphk#include "opt_ddb.h"
42164760Sjb#include "opt_printf.h"
43284192Sken#endif  /* _KERNEL */
44108678Sphk
451541Srgrimes#include <sys/param.h>
46284192Sken#ifdef _KERNEL
471541Srgrimes#include <sys/systm.h>
4891140Stanimura#include <sys/lock.h>
49131931Smarcel#include <sys/kdb.h>
5091140Stanimura#include <sys/mutex.h>
5191140Stanimura#include <sys/sx.h>
5236441Sphk#include <sys/kernel.h>
531541Srgrimes#include <sys/msgbuf.h>
5430354Sphk#include <sys/malloc.h>
55164033Srwatson#include <sys/priv.h>
561541Srgrimes#include <sys/proc.h>
57106855Smux#include <sys/stddef.h>
5890490Sphk#include <sys/sysctl.h>
591541Srgrimes#include <sys/tty.h>
601541Srgrimes#include <sys/syslog.h>
6149558Sphk#include <sys/cons.h>
6270239Sphk#include <sys/uio.h>
63284192Sken#endif
64156518Sjkim#include <sys/ctype.h>
65284192Sken#include <sys/sbuf.h>
661541Srgrimes
67108678Sphk#ifdef DDB
68108678Sphk#include <ddb/ddb.h>
69108678Sphk#endif
70108678Sphk
711541Srgrimes/*
721541Srgrimes * Note that stdarg.h and the ANSI style va_start macro is used for both
731541Srgrimes * ANSI and traditional C compilers.
741541Srgrimes */
75321107Sngie#ifdef _KERNEL
761541Srgrimes#include <machine/stdarg.h>
77321107Sngie#else
78321107Sngie#include <stdarg.h>
79321107Sngie#endif
801541Srgrimes
81321107Sngie/*
82321107Sngie * This is needed for sbuf_putbuf() when compiled into userland.  Due to the
83321107Sngie * shared nature of this file, it's the only place to put it.
84321107Sngie */
85321107Sngie#ifndef _KERNEL
86321107Sngie#include <stdio.h>
87321107Sngie#endif
88321107Sngie
89284192Sken#ifdef _KERNEL
90284192Sken
911541Srgrimes#define TOCONS	0x01
921541Srgrimes#define TOTTY	0x02
931541Srgrimes#define TOLOG	0x04
941541Srgrimes
9548728Speter/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
9697749Sdes#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
9747773Sarchie
9841479Sarchiestruct putchar_arg {
9947822Sarchie	int	flags;
10070239Sphk	int	pri;
10147822Sarchie	struct	tty *tty;
102163858Sjb	char	*p_bufr;
103163858Sjb	size_t	n_bufr;
104163858Sjb	char	*p_next;
105163858Sjb	size_t	remain;
10641479Sarchie};
10741479Sarchie
10841479Sarchiestruct snprintf_arg {
10947822Sarchie	char	*str;
11047822Sarchie	size_t	remain;
11141479Sarchie};
11241479Sarchie
11370239Sphkextern	int log_open;
11470239Sphk
11570239Sphkstatic void  msglogchar(int c, int pri);
116222537Skenstatic void  msglogstr(char *str, int pri, int filter_cr);
11792723Salfredstatic void  putchar(int ch, void *arg);
118156518Sjkimstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
11992723Salfredstatic void  snprintf_func(int ch, void *arg);
1201541Srgrimes
121338109Skevansstatic bool msgbufmapped;		/* Set when safe to use msgbuf */
12270239Sphkint msgbuftrigger;
1231541Srgrimes
124338109Skevans#ifndef BOOT_TAG_SZ
125338109Skevans#define	BOOT_TAG_SZ	32
126338109Skevans#endif
127338109Skevans#ifndef BOOT_TAG
128338109Skevans/* Tag used to mark the start of a boot in dmesg */
129338109Skevans#define	BOOT_TAG	""
130338109Skevans#endif
131338109Skevans
132338109Skevansstatic char current_boot_tag[BOOT_TAG_SZ + 1] = BOOT_TAG;
133338109SkevansSYSCTL_STRING(_kern, OID_AUTO, boot_tag, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
134338109Skevans    current_boot_tag, 0, "Tag added to dmesg at start of boot");
135338109Skevans
136267992Shselaskystatic int log_console_output = 1;
137267992ShselaskySYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
138267992Shselasky    &log_console_output, 0, "Duplicate console output to the syslog");
13995713Sdwmalone
140222537Sken/*
141222537Sken * See the comment in log_console() below for more explanation of this.
142222537Sken */
143267992Shselaskystatic int log_console_add_linefeed;
144267992ShselaskySYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
145267992Shselasky    &log_console_add_linefeed, 0, "log_console() adds extra newlines");
146222537Sken
147267992Shselaskystatic int always_console_output;
148267992ShselaskySYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
149267992Shselasky    &always_console_output, 0, "Always output to console despite TIOCCONS");
150130700Sgreen
1511541Srgrimes/*
1521541Srgrimes * Warn that a system table is full.
1531541Srgrimes */
1541541Srgrimesvoid
15570239Sphktablefull(const char *tab)
1561541Srgrimes{
1571541Srgrimes
1581541Srgrimes	log(LOG_ERR, "%s: table is full\n", tab);
1591541Srgrimes}
1601541Srgrimes
1611541Srgrimes/*
1621541Srgrimes * Uprintf prints to the controlling terminal for the current process.
1631541Srgrimes */
16449047Sdfrint
1651541Srgrimesuprintf(const char *fmt, ...)
1661541Srgrimes{
1671541Srgrimes	va_list ap;
16813446Sphk	struct putchar_arg pca;
169189102Sed	struct proc *p;
170189102Sed	struct thread *td;
17191140Stanimura	int retval;
1721541Srgrimes
173189102Sed	td = curthread;
174189102Sed	if (TD_IS_IDLETHREAD(td))
17591140Stanimura		return (0);
17691140Stanimura
177181905Sed	sx_slock(&proctree_lock);
178189102Sed	p = td->td_proc;
17991140Stanimura	PROC_LOCK(p);
18091140Stanimura	if ((p->p_flag & P_CONTROLT) == 0) {
18191140Stanimura		PROC_UNLOCK(p);
182255509Skib		sx_sunlock(&proctree_lock);
183255509Skib		return (0);
1841541Srgrimes	}
18591140Stanimura	SESS_LOCK(p->p_session);
18691140Stanimura	pca.tty = p->p_session->s_ttyp;
18791140Stanimura	SESS_UNLOCK(p->p_session);
18891140Stanimura	PROC_UNLOCK(p);
189150560Srwatson	if (pca.tty == NULL) {
190255509Skib		sx_sunlock(&proctree_lock);
191255509Skib		return (0);
192150560Srwatson	}
19391140Stanimura	pca.flags = TOTTY;
194222804Sken	pca.p_bufr = NULL;
19591140Stanimura	va_start(ap, fmt);
196181905Sed	tty_lock(pca.tty);
197255509Skib	sx_sunlock(&proctree_lock);
19891140Stanimura	retval = kvprintf(fmt, putchar, &pca, 10, ap);
199181905Sed	tty_unlock(pca.tty);
20091140Stanimura	va_end(ap);
20190490Sphk	return (retval);
2021541Srgrimes}
2031541Srgrimes
2041541Srgrimes/*
205255351Snp * tprintf and vtprintf print on the controlling terminal associated with the
206255351Snp * given session, possibly to the log as well.
2071541Srgrimes */
20869214Sphkvoid
20969214Sphktprintf(struct proc *p, int pri, const char *fmt, ...)
2101541Srgrimes{
211255351Snp	va_list ap;
212255351Snp
213255351Snp	va_start(ap, fmt);
214255351Snp	vtprintf(p, pri, fmt, ap);
215255351Snp	va_end(ap);
216255351Snp}
217255351Snp
218255351Snpvoid
219255351Snpvtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
220255351Snp{
2211541Srgrimes	struct tty *tp = NULL;
222113634Sjhb	int flags = 0;
22313446Sphk	struct putchar_arg pca;
224113634Sjhb	struct session *sess = NULL;
2251541Srgrimes
226181905Sed	sx_slock(&proctree_lock);
22770239Sphk	if (pri != -1)
22869214Sphk		flags |= TOLOG;
22991140Stanimura	if (p != NULL) {
23091140Stanimura		PROC_LOCK(p);
23191140Stanimura		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
232113634Sjhb			sess = p->p_session;
233181905Sed			sess_hold(sess);
23491140Stanimura			PROC_UNLOCK(p);
235113634Sjhb			tp = sess->s_ttyp;
236181905Sed			if (tp != NULL && tty_checkoutq(tp))
23791140Stanimura				flags |= TOTTY;
23891140Stanimura			else
23991140Stanimura				tp = NULL;
24091140Stanimura		} else
24191140Stanimura			PROC_UNLOCK(p);
24269214Sphk	}
24370239Sphk	pca.pri = pri;
24413446Sphk	pca.tty = tp;
24513446Sphk	pca.flags = flags;
246222804Sken	pca.p_bufr = NULL;
247181905Sed	if (pca.tty != NULL)
248181905Sed		tty_lock(pca.tty);
249255509Skib	sx_sunlock(&proctree_lock);
250115538Sphk	kvprintf(fmt, putchar, &pca, 10, ap);
251181905Sed	if (pca.tty != NULL)
252181905Sed		tty_unlock(pca.tty);
253143740Sphk	if (sess != NULL)
254181905Sed		sess_release(sess);
25570239Sphk	msgbuftrigger = 1;
2561541Srgrimes}
2571541Srgrimes
2581541Srgrimes/*
2591541Srgrimes * Ttyprintf displays a message on a tty; it should be used only by
2601541Srgrimes * the tty driver, or anything that knows the underlying tty will not
2611541Srgrimes * be revoke(2)'d away.  Other callers should use tprintf.
2621541Srgrimes */
26349047Sdfrint
2641541Srgrimesttyprintf(struct tty *tp, const char *fmt, ...)
2651541Srgrimes{
2661541Srgrimes	va_list ap;
26713446Sphk	struct putchar_arg pca;
26849047Sdfr	int retval;
26949047Sdfr
2701541Srgrimes	va_start(ap, fmt);
27113446Sphk	pca.tty = tp;
27213446Sphk	pca.flags = TOTTY;
273222804Sken	pca.p_bufr = NULL;
27449047Sdfr	retval = kvprintf(fmt, putchar, &pca, 10, ap);
2751541Srgrimes	va_end(ap);
27690490Sphk	return (retval);
2771541Srgrimes}
2781541Srgrimes
279263129Sbdrewerystatic int
280263129Sbdrewery_vprintf(int level, int flags, const char *fmt, va_list ap)
2811541Srgrimes{
28270239Sphk	struct putchar_arg pca;
283263129Sbdrewery	int retval;
284222537Sken#ifdef PRINTF_BUFR_SIZE
285222537Sken	char bufr[PRINTF_BUFR_SIZE];
286222537Sken#endif
2871541Srgrimes
28870239Sphk	pca.tty = NULL;
28970239Sphk	pca.pri = level;
290263129Sbdrewery	pca.flags = flags;
291222537Sken#ifdef PRINTF_BUFR_SIZE
292222537Sken	pca.p_bufr = bufr;
293222537Sken	pca.p_next = pca.p_bufr;
294222537Sken	pca.n_bufr = sizeof(bufr);
295222537Sken	pca.remain = sizeof(bufr);
296222537Sken	*pca.p_next = '\0';
297222537Sken#else
298263129Sbdrewery	/* Don't buffer console output. */
299163858Sjb	pca.p_bufr = NULL;
300222537Sken#endif
30170239Sphk
302263129Sbdrewery	retval = kvprintf(fmt, putchar, &pca, 10, ap);
30313446Sphk
304222537Sken#ifdef PRINTF_BUFR_SIZE
305222537Sken	/* Write any buffered console/log output: */
306222537Sken	if (*pca.p_bufr != '\0') {
307222537Sken		if (pca.flags & TOLOG)
308222537Sken			msglogstr(pca.p_bufr, level, /*filter_cr*/1);
309222537Sken
310222537Sken		if (pca.flags & TOCONS)
311222537Sken			cnputs(pca.p_bufr);
312222537Sken	}
313222537Sken#endif
314263129Sbdrewery
315263129Sbdrewery	return (retval);
316263129Sbdrewery}
317263129Sbdrewery
318263129Sbdrewery/*
319263129Sbdrewery * Log writes to the log buffer, and guarantees not to sleep (so can be
320263129Sbdrewery * called by interrupt routines).  If there is no process reading the
321263129Sbdrewery * log yet, it writes to the console also.
322263129Sbdrewery */
323263129Sbdreweryvoid
324263129Sbdrewerylog(int level, const char *fmt, ...)
325263129Sbdrewery{
326263129Sbdrewery	va_list ap;
327263129Sbdrewery
328263129Sbdrewery	va_start(ap, fmt);
329291058Smarkj	vlog(level, fmt, ap);
330263129Sbdrewery	va_end(ap);
331291058Smarkj}
332263129Sbdrewery
333291058Smarkjvoid
334291058Smarkjvlog(int level, const char *fmt, va_list ap)
335291058Smarkj{
336291058Smarkj
337291058Smarkj	(void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
33870240Sphk	msgbuftrigger = 1;
3391541Srgrimes}
3401541Srgrimes
34170239Sphk#define CONSCHUNK 128
34270239Sphk
34370239Sphkvoid
34470239Sphklog_console(struct uio *uio)
3451541Srgrimes{
346222537Sken	int c, error, nl;
34770239Sphk	char *consbuffer;
34870239Sphk	int pri;
3491541Srgrimes
35095713Sdwmalone	if (!log_console_output)
35195713Sdwmalone		return;
35295713Sdwmalone
35370239Sphk	pri = LOG_INFO | LOG_CONSOLE;
354131897Sphk	uio = cloneuio(uio);
355131897Sphk	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
35670239Sphk
357186383Sed	nl = 0;
35870239Sphk	while (uio->uio_resid > 0) {
359222537Sken		c = imin(uio->uio_resid, CONSCHUNK - 1);
36070239Sphk		error = uiomove(consbuffer, c, uio);
36170239Sphk		if (error != 0)
362104114Sphk			break;
363222537Sken		/* Make sure we're NUL-terminated */
364222537Sken		consbuffer[c] = '\0';
365222537Sken		if (consbuffer[c - 1] == '\n')
366222537Sken			nl = 1;
367222537Sken		else
368222537Sken			nl = 0;
369222537Sken		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
37070239Sphk	}
371222537Sken	/*
372222537Sken	 * The previous behavior in log_console() is preserved when
373222537Sken	 * log_console_add_linefeed is non-zero.  For that behavior, if an
374222537Sken	 * individual console write came in that was not terminated with a
375222537Sken	 * line feed, it would add a line feed.
376222537Sken	 *
377222537Sken	 * This results in different data in the message buffer than
378222537Sken	 * appears on the system console (which doesn't add extra line feed
379222537Sken	 * characters).
380222537Sken	 *
381222537Sken	 * A number of programs and rc scripts write a line feed, or a period
382222537Sken	 * and a line feed when they have completed their operation.  On
383222537Sken	 * the console, this looks seamless, but when displayed with
384222537Sken	 * 'dmesg -a', you wind up with output that looks like this:
385222537Sken	 *
386222537Sken	 * Updating motd:
387222537Sken	 * .
388222537Sken	 *
389222537Sken	 * On the console, it looks like this:
390222537Sken	 * Updating motd:.
391222537Sken	 *
392222537Sken	 * We could add logic to detect that situation, or just not insert
393222537Sken	 * the extra newlines.  Set the kern.log_console_add_linefeed
394222537Sken	 * sysctl/tunable variable to get the old behavior.
395222537Sken	 */
396222537Sken	if (!nl && log_console_add_linefeed) {
397222537Sken		consbuffer[0] = '\n';
398222537Sken		consbuffer[1] = '\0';
399222537Sken		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
400222537Sken	}
40170240Sphk	msgbuftrigger = 1;
402131897Sphk	free(uio, M_IOV);
403131897Sphk	free(consbuffer, M_TEMP);
4041541Srgrimes}
4051541Srgrimes
40615680Sgpalmerint
4071541Srgrimesprintf(const char *fmt, ...)
4081541Srgrimes{
4091541Srgrimes	va_list ap;
41013694Sgibbs	int retval;
4111541Srgrimes
4121541Srgrimes	va_start(ap, fmt);
413189104Sed	retval = vprintf(fmt, ap);
4141541Srgrimes	va_end(ap);
415163858Sjb
41690490Sphk	return (retval);
4171541Srgrimes}
4181541Srgrimes
41949047Sdfrint
42013446Sphkvprintf(const char *fmt, va_list ap)
42113446Sphk{
42249047Sdfr	int retval;
42313446Sphk
424263129Sbdrewery	retval = _vprintf(-1, TOCONS | TOLOG, fmt, ap);
425163858Sjb
42613446Sphk	if (!panicstr)
42770240Sphk		msgbuftrigger = 1;
428163858Sjb
42990490Sphk	return (retval);
43013446Sphk}
43113446Sphk
432163858Sjbstatic void
433321107Sngieprf_putbuf(char *bufr, int flags, int pri)
434321107Sngie{
435321107Sngie
436321107Sngie	if (flags & TOLOG)
437321107Sngie		msglogstr(bufr, pri, /*filter_cr*/1);
438321107Sngie
439321107Sngie	if (flags & TOCONS) {
440321107Sngie		if ((panicstr == NULL) && (constty != NULL))
441321107Sngie			msgbuf_addstr(&consmsgbuf, -1,
442321107Sngie			    bufr, /*filter_cr*/ 0);
443321107Sngie
444321107Sngie		if ((constty == NULL) ||(always_console_output))
445321107Sngie			cnputs(bufr);
446321107Sngie	}
447321107Sngie}
448321107Sngie
449321107Sngiestatic void
450222537Skenputbuf(int c, struct putchar_arg *ap)
451163858Sjb{
452163858Sjb	/* Check if no console output buffer was provided. */
453222537Sken	if (ap->p_bufr == NULL) {
454163858Sjb		/* Output direct to the console. */
455222537Sken		if (ap->flags & TOCONS)
456222537Sken			cnputc(c);
457222537Sken
458222537Sken		if (ap->flags & TOLOG)
459222537Sken			msglogchar(c, ap->pri);
460222537Sken	} else {
461163858Sjb		/* Buffer the character: */
462163858Sjb		*ap->p_next++ = c;
463163858Sjb		ap->remain--;
464163858Sjb
465163858Sjb		/* Always leave the buffer zero terminated. */
466163858Sjb		*ap->p_next = '\0';
467163858Sjb
468163858Sjb		/* Check if the buffer needs to be flushed. */
469222537Sken		if (ap->remain == 2 || c == '\n') {
470321107Sngie			prf_putbuf(ap->p_bufr, ap->flags, ap->pri);
471222537Sken
472163858Sjb			ap->p_next = ap->p_bufr;
473163858Sjb			ap->remain = ap->n_bufr;
474163858Sjb			*ap->p_next = '\0';
475163858Sjb		}
476222537Sken
477222537Sken		/*
478222537Sken		 * Since we fill the buffer up one character at a time,
479222537Sken		 * this should not happen.  We should always catch it when
480222537Sken		 * ap->remain == 2 (if not sooner due to a newline), flush
481222537Sken		 * the buffer and move on.  One way this could happen is
482222537Sken		 * if someone sets PRINTF_BUFR_SIZE to 1 or something
483222537Sken		 * similarly silly.
484222537Sken		 */
485222537Sken		KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
486222537Sken		    ap->remain));
487163858Sjb	}
488163858Sjb}
489163858Sjb
4901541Srgrimes/*
49113446Sphk * Print a character on console or users terminal.  If destination is
49236441Sphk * the console then the last bunch of characters are saved in msgbuf for
49313446Sphk * inspection later.
49413446Sphk */
49513446Sphkstatic void
49613446Sphkputchar(int c, void *arg)
49713446Sphk{
49813446Sphk	struct putchar_arg *ap = (struct putchar_arg*) arg;
49913446Sphk	struct tty *tp = ap->tty;
500163858Sjb	int flags = ap->flags;
501116663Siedowse
502116664Siedowse	/* Don't use the tty code after a panic or while in ddb. */
503163858Sjb	if (kdb_active) {
504116663Siedowse		if (c != '\0')
505116663Siedowse			cnputc(c);
506226435Smarcel		return;
507226435Smarcel	}
508222537Sken
509226435Smarcel	if ((flags & TOTTY) && tp != NULL && panicstr == NULL)
510226435Smarcel		tty_putchar(tp, c);
511226435Smarcel
512226435Smarcel	if ((flags & (TOCONS | TOLOG)) && c != '\0')
513226435Smarcel		putbuf(c, ap);
51413446Sphk}
51513446Sphk
51613446Sphk/*
51713446Sphk * Scaled down version of sprintf(3).
51813446Sphk */
51913446Sphkint
52013446Sphksprintf(char *buf, const char *cfmt, ...)
52113446Sphk{
52213446Sphk	int retval;
52313446Sphk	va_list ap;
52413446Sphk
52513446Sphk	va_start(ap, cfmt);
52613446Sphk	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
52713494Sphk	buf[retval] = '\0';
52813446Sphk	va_end(ap);
52990490Sphk	return (retval);
53013446Sphk}
53113446Sphk
53213446Sphk/*
53338874Sache * Scaled down version of vsprintf(3).
53438874Sache */
53538874Sacheint
53638874Sachevsprintf(char *buf, const char *cfmt, va_list ap)
53738874Sache{
53838874Sache	int retval;
53938874Sache
54038874Sache	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
54138874Sache	buf[retval] = '\0';
54290490Sphk	return (retval);
54338874Sache}
54438874Sache
54538874Sache/*
54641479Sarchie * Scaled down version of snprintf(3).
54741479Sarchie */
54841479Sarchieint
54941479Sarchiesnprintf(char *str, size_t size, const char *format, ...)
55041479Sarchie{
55141479Sarchie	int retval;
55241479Sarchie	va_list ap;
55341479Sarchie
55441479Sarchie	va_start(ap, format);
55541479Sarchie	retval = vsnprintf(str, size, format, ap);
55641479Sarchie	va_end(ap);
55741479Sarchie	return(retval);
55841479Sarchie}
55941479Sarchie
56041479Sarchie/*
56141479Sarchie * Scaled down version of vsnprintf(3).
56241479Sarchie */
56341479Sarchieint
56441479Sarchievsnprintf(char *str, size_t size, const char *format, va_list ap)
56541479Sarchie{
56641479Sarchie	struct snprintf_arg info;
56741479Sarchie	int retval;
56841479Sarchie
56941479Sarchie	info.str = str;
57041479Sarchie	info.remain = size;
57141479Sarchie	retval = kvprintf(format, snprintf_func, &info, 10, ap);
57241479Sarchie	if (info.remain >= 1)
57341479Sarchie		*info.str++ = '\0';
57490490Sphk	return (retval);
57541479Sarchie}
57641479Sarchie
577110316Sphk/*
578110316Sphk * Kernel version which takes radix argument vsnprintf(3).
579110316Sphk */
580110316Sphkint
581110316Sphkvsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
582110316Sphk{
583110316Sphk	struct snprintf_arg info;
584110316Sphk	int retval;
585110316Sphk
586110316Sphk	info.str = str;
587110316Sphk	info.remain = size;
588110316Sphk	retval = kvprintf(format, snprintf_func, &info, radix, ap);
589110316Sphk	if (info.remain >= 1)
590110316Sphk		*info.str++ = '\0';
591110316Sphk	return (retval);
592110316Sphk}
593110316Sphk
59441479Sarchiestatic void
59541479Sarchiesnprintf_func(int ch, void *arg)
59641479Sarchie{
59741479Sarchie	struct snprintf_arg *const info = arg;
59841479Sarchie
59941479Sarchie	if (info->remain >= 2) {
60041479Sarchie		*info->str++ = ch;
60141479Sarchie		info->remain--;
60241479Sarchie	}
60341479Sarchie}
60441479Sarchie
60541479Sarchie/*
60648728Speter * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
60747822Sarchie * order; return an optional length and a pointer to the last character
60847822Sarchie * written in the buffer (i.e., the first character of the string).
60947822Sarchie * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
61013446Sphk */
61113446Sphkstatic char *
612156518Sjkimksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
61347822Sarchie{
614156518Sjkim	char *p, c;
61513446Sphk
61647822Sarchie	p = nbuf;
61747773Sarchie	*p = '\0';
61813446Sphk	do {
619156518Sjkim		c = hex2ascii(num % base);
620156518Sjkim		*++p = upper ? toupper(c) : c;
62197749Sdes	} while (num /= base);
62213446Sphk	if (lenp)
62347822Sarchie		*lenp = p - nbuf;
62413446Sphk	return (p);
62513446Sphk}
62613446Sphk
62713446Sphk/*
6281541Srgrimes * Scaled down version of printf(3).
6291541Srgrimes *
6301541Srgrimes * Two additional formats:
6311541Srgrimes *
6321541Srgrimes * The format %b is supported to decode error registers.
6331541Srgrimes * Its usage is:
6341541Srgrimes *
6351541Srgrimes *	printf("reg=%b\n", regval, "<base><arg>*");
6361541Srgrimes *
6371541Srgrimes * where <base> is the output base expressed as a control character, e.g.
6381541Srgrimes * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
6391541Srgrimes * the first of which gives the bit number to be inspected (origin 1), and
6401541Srgrimes * the next characters (up to a control character, i.e. a character <= 32),
6411541Srgrimes * give the name of the register.  Thus:
6421541Srgrimes *
643277560Sdanfe *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE");
6441541Srgrimes *
6451541Srgrimes * would produce output:
6461541Srgrimes *
6471541Srgrimes *	reg=3<BITTWO,BITONE>
6481541Srgrimes *
64913618Sphk * XXX:  %D  -- Hexdump, takes pointer and separator string:
65013618Sphk *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
65113618Sphk *		("%*D", len, ptr, " " -> XX XX XX XX ...
6521541Srgrimes */
65313446Sphkint
65413446Sphkkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
6551541Srgrimes{
65613446Sphk#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
65747773Sarchie	char nbuf[MAXNBUF];
65897749Sdes	char *d;
65997749Sdes	const char *p, *percent, *q;
66013618Sphk	u_char *up;
66113446Sphk	int ch, n;
66297749Sdes	uintmax_t num;
66348714Speter	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
664125985Snjl	int cflag, hflag, jflag, tflag, zflag;
665156518Sjkim	int dwidth, upper;
6661541Srgrimes	char padc;
667149756Sphk	int stop = 0, retval = 0;
6681541Srgrimes
66997749Sdes	num = 0;
67013494Sphk	if (!func)
67113446Sphk		d = (char *) arg;
67213446Sphk	else
67313494Sphk		d = NULL;
67413446Sphk
6755261Sdg	if (fmt == NULL)
6765288Sbde		fmt = "(fmt null)\n";
67713563Sphk
67813618Sphk	if (radix < 2 || radix > 36)
67913563Sphk		radix = 10;
68013563Sphk
6811541Srgrimes	for (;;) {
6821541Srgrimes		padc = ' ';
6831541Srgrimes		width = 0;
684149756Sphk		while ((ch = (u_char)*fmt++) != '%' || stop) {
68597750Sdes			if (ch == '\0')
68690490Sphk				return (retval);
68713446Sphk			PCHAR(ch);
6881541Srgrimes		}
68997749Sdes		percent = fmt - 1;
69048714Speter		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
691156518Sjkim		sign = 0; dot = 0; dwidth = 0; upper = 0;
692125985Snjl		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
69317974Sbdereswitch:	switch (ch = (u_char)*fmt++) {
69413466Sphk		case '.':
69513466Sphk			dot = 1;
69613466Sphk			goto reswitch;
69713446Sphk		case '#':
69813446Sphk			sharpflag = 1;
69913446Sphk			goto reswitch;
70013446Sphk		case '+':
70113446Sphk			sign = 1;
70213446Sphk			goto reswitch;
70313446Sphk		case '-':
70413446Sphk			ladjust = 1;
70513446Sphk			goto reswitch;
70613446Sphk		case '%':
70713446Sphk			PCHAR(ch);
70813446Sphk			break;
70913446Sphk		case '*':
71013501Sphk			if (!dot) {
71113501Sphk				width = va_arg(ap, int);
71213501Sphk				if (width < 0) {
71313501Sphk					ladjust = !ladjust;
71413501Sphk					width = -width;
71513501Sphk				}
71613501Sphk			} else {
71713501Sphk				dwidth = va_arg(ap, int);
71813446Sphk			}
71913446Sphk			goto reswitch;
7201541Srgrimes		case '0':
72113480Sphk			if (!dot) {
72213480Sphk				padc = '0';
72313480Sphk				goto reswitch;
72413480Sphk			}
725336550Smarkj			/* FALLTHROUGH */
7261541Srgrimes		case '1': case '2': case '3': case '4':
7271541Srgrimes		case '5': case '6': case '7': case '8': case '9':
72813480Sphk				for (n = 0;; ++fmt) {
72913480Sphk					n = n * 10 + ch - '0';
73013480Sphk					ch = *fmt;
73113480Sphk					if (ch < '0' || ch > '9')
73213480Sphk						break;
73313480Sphk				}
73413480Sphk			if (dot)
73513480Sphk				dwidth = n;
73613480Sphk			else
73713480Sphk				width = n;
7381541Srgrimes			goto reswitch;
7391541Srgrimes		case 'b':
740108890Sjhb			num = (u_int)va_arg(ap, int);
7411541Srgrimes			p = va_arg(ap, char *);
742156518Sjkim			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
74313446Sphk				PCHAR(*q--);
7441541Srgrimes
74597749Sdes			if (num == 0)
7461541Srgrimes				break;
7471541Srgrimes
7483308Sphk			for (tmp = 0; *p;) {
7493308Sphk				n = *p++;
75097749Sdes				if (num & (1 << (n - 1))) {
75113446Sphk					PCHAR(tmp ? ',' : '<');
7521541Srgrimes					for (; (n = *p) > ' '; ++p)
75313446Sphk						PCHAR(n);
7541541Srgrimes					tmp = 1;
7551541Srgrimes				} else
7561541Srgrimes					for (; *p > ' '; ++p)
7571541Srgrimes						continue;
7581541Srgrimes			}
7591541Srgrimes			if (tmp)
76013446Sphk				PCHAR('>');
7611541Srgrimes			break;
7621541Srgrimes		case 'c':
763301750Scem			width -= 1;
764301750Scem
765301750Scem			if (!ladjust && width > 0)
766301750Scem				while (width--)
767301750Scem					PCHAR(padc);
76813446Sphk			PCHAR(va_arg(ap, int));
769301750Scem			if (ladjust && width > 0)
770301750Scem				while (width--)
771301750Scem					PCHAR(padc);
7721541Srgrimes			break;
77313618Sphk		case 'D':
77413618Sphk			up = va_arg(ap, u_char *);
77513618Sphk			p = va_arg(ap, char *);
77613618Sphk			if (!width)
77713618Sphk				width = 16;
77813618Sphk			while(width--) {
77913618Sphk				PCHAR(hex2ascii(*up >> 4));
78013618Sphk				PCHAR(hex2ascii(*up & 0x0f));
78113618Sphk				up++;
78213618Sphk				if (width)
78313618Sphk					for (q=p;*q;q++)
78413618Sphk						PCHAR(*q);
78513618Sphk			}
78613618Sphk			break;
7871541Srgrimes		case 'd':
78899459Simp		case 'i':
78997749Sdes			base = 10;
79013446Sphk			sign = 1;
79197749Sdes			goto handle_sign;
792125985Snjl		case 'h':
793125985Snjl			if (hflag) {
794125985Snjl				hflag = 0;
795125985Snjl				cflag = 1;
796125985Snjl			} else
797125985Snjl				hflag = 1;
798125985Snjl			goto reswitch;
79997749Sdes		case 'j':
80097749Sdes			jflag = 1;
80197749Sdes			goto reswitch;
80213446Sphk		case 'l':
80349502Sgreen			if (lflag) {
80449502Sgreen				lflag = 0;
80549502Sgreen				qflag = 1;
80649502Sgreen			} else
80749502Sgreen				lflag = 1;
80813446Sphk			goto reswitch;
80997749Sdes		case 'n':
81097749Sdes			if (jflag)
81197749Sdes				*(va_arg(ap, intmax_t *)) = retval;
81297749Sdes			else if (qflag)
81397749Sdes				*(va_arg(ap, quad_t *)) = retval;
81448714Speter			else if (lflag)
81597749Sdes				*(va_arg(ap, long *)) = retval;
816105954Smux			else if (zflag)
817105954Smux				*(va_arg(ap, size_t *)) = retval;
818125985Snjl			else if (hflag)
819125985Snjl				*(va_arg(ap, short *)) = retval;
820125985Snjl			else if (cflag)
821125985Snjl				*(va_arg(ap, char *)) = retval;
82248714Speter			else
82397749Sdes				*(va_arg(ap, int *)) = retval;
82497749Sdes			break;
82597749Sdes		case 'o':
8261541Srgrimes			base = 8;
82797749Sdes			goto handle_nosign;
8289224Sbde		case 'p':
8299224Sbde			base = 16;
83038224Sbde			sharpflag = (width == 0);
83197749Sdes			sign = 0;
83297749Sdes			num = (uintptr_t)va_arg(ap, void *);
83397749Sdes			goto number;
83448714Speter		case 'q':
83548714Speter			qflag = 1;
83648714Speter			goto reswitch;
83737505Sbde		case 'r':
83837505Sbde			base = radix;
83997749Sdes			if (sign)
84097749Sdes				goto handle_sign;
84197749Sdes			goto handle_nosign;
84213446Sphk		case 's':
84313446Sphk			p = va_arg(ap, char *);
84413446Sphk			if (p == NULL)
84513446Sphk				p = "(null)";
84613466Sphk			if (!dot)
84713466Sphk				n = strlen (p);
84813466Sphk			else
84913480Sphk				for (n = 0; n < dwidth && p[n]; n++)
85013466Sphk					continue;
85113480Sphk
85213466Sphk			width -= n;
85313480Sphk
85413446Sphk			if (!ladjust && width > 0)
85513446Sphk				while (width--)
85613446Sphk					PCHAR(padc);
85713466Sphk			while (n--)
85813446Sphk				PCHAR(*p++);
85913446Sphk			if (ladjust && width > 0)
86013446Sphk				while (width--)
86113446Sphk					PCHAR(padc);
86213446Sphk			break;
863106855Smux		case 't':
864106855Smux			tflag = 1;
865106855Smux			goto reswitch;
8661541Srgrimes		case 'u':
8671541Srgrimes			base = 10;
86897749Sdes			goto handle_nosign;
869156518Sjkim		case 'X':
870156518Sjkim			upper = 1;
8711541Srgrimes		case 'x':
8721541Srgrimes			base = 16;
87397749Sdes			goto handle_nosign;
874105954Smux		case 'y':
87597749Sdes			base = 16;
876104924Sjhb			sign = 1;
877104924Sjhb			goto handle_sign;
878105954Smux		case 'z':
879105954Smux			zflag = 1;
880105954Smux			goto reswitch;
88197749Sdeshandle_nosign:
88297749Sdes			sign = 0;
88397749Sdes			if (jflag)
88497749Sdes				num = va_arg(ap, uintmax_t);
88597749Sdes			else if (qflag)
88697749Sdes				num = va_arg(ap, u_quad_t);
887106855Smux			else if (tflag)
888106855Smux				num = va_arg(ap, ptrdiff_t);
88948714Speter			else if (lflag)
89097749Sdes				num = va_arg(ap, u_long);
891105954Smux			else if (zflag)
892105954Smux				num = va_arg(ap, size_t);
893125985Snjl			else if (hflag)
894125985Snjl				num = (u_short)va_arg(ap, int);
895125985Snjl			else if (cflag)
896125985Snjl				num = (u_char)va_arg(ap, int);
89748714Speter			else
89897749Sdes				num = va_arg(ap, u_int);
89937505Sbde			goto number;
90097749Sdeshandle_sign:
90197749Sdes			if (jflag)
90297749Sdes				num = va_arg(ap, intmax_t);
90397749Sdes			else if (qflag)
90497749Sdes				num = va_arg(ap, quad_t);
905106855Smux			else if (tflag)
906106855Smux				num = va_arg(ap, ptrdiff_t);
90797749Sdes			else if (lflag)
90897749Sdes				num = va_arg(ap, long);
909105954Smux			else if (zflag)
910185036Sdelphij				num = va_arg(ap, ssize_t);
911125985Snjl			else if (hflag)
912125985Snjl				num = (short)va_arg(ap, int);
913125985Snjl			else if (cflag)
914125985Snjl				num = (char)va_arg(ap, int);
91597749Sdes			else
91697749Sdes				num = va_arg(ap, int);
91797749Sdesnumber:
91897749Sdes			if (sign && (intmax_t)num < 0) {
91997749Sdes				neg = 1;
92097749Sdes				num = -(intmax_t)num;
92113446Sphk			}
922209836Sjkim			p = ksprintn(nbuf, num, base, &n, upper);
923209836Sjkim			tmp = 0;
92497749Sdes			if (sharpflag && num != 0) {
92513446Sphk				if (base == 8)
92613446Sphk					tmp++;
92713446Sphk				else if (base == 16)
92813446Sphk					tmp += 2;
92913446Sphk			}
93013446Sphk			if (neg)
93113446Sphk				tmp++;
93213446Sphk
933209836Sjkim			if (!ladjust && padc == '0')
934209836Sjkim				dwidth = width - tmp;
935209949Sjkim			width -= tmp + imax(dwidth, n);
936209836Sjkim			dwidth -= n;
937209836Sjkim			if (!ladjust)
938209836Sjkim				while (width-- > 0)
939209836Sjkim					PCHAR(' ');
94013446Sphk			if (neg)
94113446Sphk				PCHAR('-');
94297749Sdes			if (sharpflag && num != 0) {
94313446Sphk				if (base == 8) {
94413446Sphk					PCHAR('0');
94513446Sphk				} else if (base == 16) {
94613446Sphk					PCHAR('0');
94713446Sphk					PCHAR('x');
94813446Sphk				}
94913446Sphk			}
950209836Sjkim			while (dwidth-- > 0)
951209836Sjkim				PCHAR('0');
95213446Sphk
9533308Sphk			while (*p)
95413446Sphk				PCHAR(*p--);
95513446Sphk
956209836Sjkim			if (ladjust)
957209836Sjkim				while (width-- > 0)
958209836Sjkim					PCHAR(' ');
95913446Sphk
9601541Srgrimes			break;
9611541Srgrimes		default:
96297749Sdes			while (percent < fmt)
96397749Sdes				PCHAR(*percent++);
964149756Sphk			/*
965277560Sdanfe			 * Since we ignore a formatting argument it is no
966149756Sphk			 * longer safe to obey the remaining formatting
967149756Sphk			 * arguments as the arguments will no longer match
968149756Sphk			 * the format specs.
969149756Sphk			 */
970149756Sphk			stop = 1;
97113446Sphk			break;
9721541Srgrimes		}
9731541Srgrimes	}
97413446Sphk#undef PCHAR
9751541Srgrimes}
9761541Srgrimes
9771541Srgrimes/*
97870239Sphk * Put character in log buffer with a particular priority.
9791541Srgrimes */
9801541Srgrimesstatic void
98170239Sphkmsglogchar(int c, int pri)
9821541Srgrimes{
98370239Sphk	static int lastpri = -1;
98470239Sphk	static int dangling;
98570239Sphk	char nbuf[MAXNBUF];
98670239Sphk	char *p;
9871541Srgrimes
98870239Sphk	if (!msgbufmapped)
98970239Sphk		return;
99070239Sphk	if (c == '\0' || c == '\r')
99170239Sphk		return;
99270239Sphk	if (pri != -1 && pri != lastpri) {
99370239Sphk		if (dangling) {
994116660Siedowse			msgbuf_addchar(msgbufp, '\n');
99570239Sphk			dangling = 0;
9966561Sbde		}
997116660Siedowse		msgbuf_addchar(msgbufp, '<');
998156518Sjkim		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL, 0); *p;)
999116660Siedowse			msgbuf_addchar(msgbufp, *p--);
1000116660Siedowse		msgbuf_addchar(msgbufp, '>');
100170239Sphk		lastpri = pri;
10021541Srgrimes	}
1003116660Siedowse	msgbuf_addchar(msgbufp, c);
100470239Sphk	if (c == '\n') {
100570239Sphk		dangling = 0;
100670239Sphk		lastpri = -1;
100770239Sphk	} else {
100870239Sphk		dangling = 1;
100970239Sphk	}
10101541Srgrimes}
101136441Sphk
1012222537Skenstatic void
1013222537Skenmsglogstr(char *str, int pri, int filter_cr)
1014222537Sken{
1015222537Sken	if (!msgbufmapped)
1016222537Sken		return;
1017222537Sken
1018222537Sken	msgbuf_addstr(msgbufp, pri, str, filter_cr);
1019222537Sken}
1020222537Sken
102136441Sphkvoid
1022106917Stmmmsgbufinit(void *ptr, int size)
102336441Sphk{
102436441Sphk	char *cp;
102547678Sjlemon	static struct msgbuf *oldp = NULL;
1026338109Skevans	bool print_boot_tag;
102736441Sphk
102886238Siedowse	size -= sizeof(*msgbufp);
102936441Sphk	cp = (char *)ptr;
1030338109Skevans	print_boot_tag = !msgbufmapped;
1031338109Skevans	/* Attempt to fetch kern.boot_tag tunable on first mapping */
1032338109Skevans	if (!msgbufmapped)
1033338109Skevans		TUNABLE_STR_FETCH("kern.boot_tag", current_boot_tag,
1034338109Skevans		    sizeof(current_boot_tag));
1035116660Siedowse	msgbufp = (struct msgbuf *)(cp + size);
1036116660Siedowse	msgbuf_reinit(msgbufp, cp, size);
103747678Sjlemon	if (msgbufmapped && oldp != msgbufp)
1038116660Siedowse		msgbuf_copy(oldp, msgbufp);
1039338109Skevans	msgbufmapped = true;
1040338109Skevans	if (print_boot_tag && *current_boot_tag != '\0')
1041338109Skevans		printf("%s\n", current_boot_tag);
104247678Sjlemon	oldp = msgbufp;
104336441Sphk}
104436441Sphk
104579153Stmm/* Sysctls for accessing/clearing the msgbuf */
104679153Stmmstatic int
104779153Stmmsysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
104879153Stmm{
1049116660Siedowse	char buf[128];
1050116660Siedowse	u_int seq;
1051116660Siedowse	int error, len;
105279153Stmm
1053339446Sjamie	error = priv_check(req->td, PRIV_MSGBUF);
1054339446Sjamie	if (error)
1055339446Sjamie		return (error);
105687150Srwatson
1057116660Siedowse	/* Read the whole buffer, one chunk at a time. */
1058198860Sed	mtx_lock(&msgbuf_lock);
1059116660Siedowse	msgbuf_peekbytes(msgbufp, NULL, 0, &seq);
1060198860Sed	for (;;) {
1061198860Sed		len = msgbuf_peekbytes(msgbufp, buf, sizeof(buf), &seq);
1062198860Sed		mtx_unlock(&msgbuf_lock);
1063198860Sed		if (len == 0)
1064280016Sian			return (SYSCTL_OUT(req, "", 1)); /* add nulterm */
1065198860Sed
1066116660Siedowse		error = sysctl_handle_opaque(oidp, buf, len, req);
1067116660Siedowse		if (error)
1068116660Siedowse			return (error);
1069198860Sed
1070198860Sed		mtx_lock(&msgbuf_lock);
107179153Stmm	}
107279153Stmm}
107379153Stmm
1074198860SedSYSCTL_PROC(_kern, OID_AUTO, msgbuf,
1075198860Sed    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
1076188057Simp    NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
107779153Stmm
1078116660Siedowsestatic int msgbuf_clearflag;
107979153Stmm
108079153Stmmstatic int
108179153Stmmsysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
108279153Stmm{
108379153Stmm	int error;
108479153Stmm	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
108579153Stmm	if (!error && req->newptr) {
1086198860Sed		mtx_lock(&msgbuf_lock);
1087116660Siedowse		msgbuf_clear(msgbufp);
1088198860Sed		mtx_unlock(&msgbuf_lock);
1089116660Siedowse		msgbuf_clearflag = 0;
109079153Stmm	}
109179153Stmm	return (error);
109279153Stmm}
109379153Stmm
109479153StmmSYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
1095198860Sed    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_MPSAFE,
1096198860Sed    &msgbuf_clearflag, 0, sysctl_kern_msgbuf_clear, "I",
1097198860Sed    "Clear kernel message buffer");
109879153Stmm
109936441Sphk#ifdef DDB
110036441Sphk
110136441SphkDB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
110236441Sphk{
1103160312Sjhb	int i, j;
110436441Sphk
110536441Sphk	if (!msgbufmapped) {
110636441Sphk		db_printf("msgbuf not mapped yet\n");
110736441Sphk		return;
110836441Sphk	}
110936441Sphk	db_printf("msgbufp = %p\n", msgbufp);
1110116660Siedowse	db_printf("magic = %x, size = %d, r= %u, w = %u, ptr = %p, cksum= %u\n",
1111116660Siedowse	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_rseq,
1112116660Siedowse	    msgbufp->msg_wseq, msgbufp->msg_ptr, msgbufp->msg_cksum);
1113160312Sjhb	for (i = 0; i < msgbufp->msg_size && !db_pager_quit; i++) {
1114116660Siedowse		j = MSGBUF_SEQ_TO_POS(msgbufp, i + msgbufp->msg_rseq);
111536441Sphk		db_printf("%c", msgbufp->msg_ptr[j]);
111636441Sphk	}
111736441Sphk	db_printf("\n");
111836441Sphk}
111936441Sphk
112036441Sphk#endif /* DDB */
1121123215Sscottl
1122123215Sscottlvoid
1123144706Sphkhexdump(const void *ptr, int length, const char *hdr, int flags)
1124123215Sscottl{
1125123215Sscottl	int i, j, k;
1126123215Sscottl	int cols;
1127144706Sphk	const unsigned char *cp;
1128123215Sscottl	char delim;
1129123215Sscottl
1130123215Sscottl	if ((flags & HD_DELIM_MASK) != 0)
1131123215Sscottl		delim = (flags & HD_DELIM_MASK) >> 8;
1132123215Sscottl	else
1133123215Sscottl		delim = ' ';
1134123215Sscottl
1135123215Sscottl	if ((flags & HD_COLUMN_MASK) != 0)
1136123215Sscottl		cols = flags & HD_COLUMN_MASK;
1137123215Sscottl	else
1138123215Sscottl		cols = 16;
1139123215Sscottl
1140123215Sscottl	cp = ptr;
1141123215Sscottl	for (i = 0; i < length; i+= cols) {
1142123215Sscottl		if (hdr != NULL)
1143123215Sscottl			printf("%s", hdr);
1144123215Sscottl
1145123215Sscottl		if ((flags & HD_OMIT_COUNT) == 0)
1146123215Sscottl			printf("%04x  ", i);
1147123215Sscottl
1148123215Sscottl		if ((flags & HD_OMIT_HEX) == 0) {
1149123215Sscottl			for (j = 0; j < cols; j++) {
1150123215Sscottl				k = i + j;
1151123215Sscottl				if (k < length)
1152123215Sscottl					printf("%c%02x", delim, cp[k]);
1153123215Sscottl				else
1154123215Sscottl					printf("   ");
1155123215Sscottl			}
1156123215Sscottl		}
1157123215Sscottl
1158123215Sscottl		if ((flags & HD_OMIT_CHARS) == 0) {
1159123215Sscottl			printf("  |");
1160123215Sscottl			for (j = 0; j < cols; j++) {
1161123215Sscottl				k = i + j;
1162123215Sscottl				if (k >= length)
1163123215Sscottl					printf(" ");
1164123215Sscottl				else if (cp[k] >= ' ' && cp[k] <= '~')
1165123215Sscottl					printf("%c", cp[k]);
1166123215Sscottl				else
1167123215Sscottl					printf(".");
1168123215Sscottl			}
1169156001Sscottl			printf("|");
1170123215Sscottl		}
1171156001Sscottl		printf("\n");
1172123215Sscottl	}
1173123215Sscottl}
1174284192Sken#endif /* _KERNEL */
1175284192Sken
1176284192Skenvoid
1177284192Skensbuf_hexdump(struct sbuf *sb, const void *ptr, int length, const char *hdr,
1178284192Sken	     int flags)
1179284192Sken{
1180284192Sken	int i, j, k;
1181284192Sken	int cols;
1182284192Sken	const unsigned char *cp;
1183284192Sken	char delim;
1184284192Sken
1185284192Sken	if ((flags & HD_DELIM_MASK) != 0)
1186284192Sken		delim = (flags & HD_DELIM_MASK) >> 8;
1187284192Sken	else
1188284192Sken		delim = ' ';
1189284192Sken
1190284192Sken	if ((flags & HD_COLUMN_MASK) != 0)
1191284192Sken		cols = flags & HD_COLUMN_MASK;
1192284192Sken	else
1193284192Sken		cols = 16;
1194284192Sken
1195284192Sken	cp = ptr;
1196284192Sken	for (i = 0; i < length; i+= cols) {
1197284192Sken		if (hdr != NULL)
1198284192Sken			sbuf_printf(sb, "%s", hdr);
1199284192Sken
1200284192Sken		if ((flags & HD_OMIT_COUNT) == 0)
1201284192Sken			sbuf_printf(sb, "%04x  ", i);
1202284192Sken
1203284192Sken		if ((flags & HD_OMIT_HEX) == 0) {
1204284192Sken			for (j = 0; j < cols; j++) {
1205284192Sken				k = i + j;
1206284192Sken				if (k < length)
1207284192Sken					sbuf_printf(sb, "%c%02x", delim, cp[k]);
1208284192Sken				else
1209284192Sken					sbuf_printf(sb, "   ");
1210284192Sken			}
1211284192Sken		}
1212284192Sken
1213284192Sken		if ((flags & HD_OMIT_CHARS) == 0) {
1214284192Sken			sbuf_printf(sb, "  |");
1215284192Sken			for (j = 0; j < cols; j++) {
1216284192Sken				k = i + j;
1217284192Sken				if (k >= length)
1218284192Sken					sbuf_printf(sb, " ");
1219284192Sken				else if (cp[k] >= ' ' && cp[k] <= '~')
1220284192Sken					sbuf_printf(sb, "%c", cp[k]);
1221284192Sken				else
1222284192Sken					sbuf_printf(sb, ".");
1223284192Sken			}
1224284192Sken			sbuf_printf(sb, "|");
1225284192Sken		}
1226284192Sken		sbuf_printf(sb, "\n");
1227284192Sken	}
1228284192Sken}
1229284192Sken
1230303432Skib#ifdef _KERNEL
1231303432Skibvoid
1232303432Skibcounted_warning(unsigned *counter, const char *msg)
1233303432Skib{
1234303432Skib	struct thread *td;
1235303432Skib	unsigned c;
1236303432Skib
1237303432Skib	for (;;) {
1238303432Skib		c = *counter;
1239303432Skib		if (c == 0)
1240303432Skib			break;
1241303432Skib		if (atomic_cmpset_int(counter, c, c - 1)) {
1242303432Skib			td = curthread;
1243303432Skib			log(LOG_INFO, "pid %d (%s) %s%s\n",
1244303432Skib			    td->td_proc->p_pid, td->td_name, msg,
1245303432Skib			    c > 1 ? "" : " - not logging anymore");
1246303432Skib			break;
1247303432Skib		}
1248303432Skib	}
1249303432Skib}
1250303432Skib#endif
1251321107Sngie
1252321107Sngie#ifdef _KERNEL
1253321107Sngievoid
1254321107Sngiesbuf_putbuf(struct sbuf *sb)
1255321107Sngie{
1256321107Sngie
1257321107Sngie	prf_putbuf(sbuf_data(sb), TOLOG | TOCONS, -1);
1258321107Sngie}
1259321107Sngie#else
1260321107Sngievoid
1261321107Sngiesbuf_putbuf(struct sbuf *sb)
1262321107Sngie{
1263321107Sngie
1264321107Sngie	printf("%s", sbuf_data(sb));
1265321107Sngie}
1266321107Sngie#endif
1267