18fb65cergrimes/*-
24736ccfpfg * SPDX-License-Identifier: BSD-3-Clause
34736ccfpfg *
48fb65cergrimes * Copyright (c) 1986, 1988, 1991, 1993
58fb65cergrimes *	The Regents of the University of California.  All rights reserved.
68fb65cergrimes * (c) UNIX System Laboratories, Inc.
78fb65cergrimes * All or some portions of this file are derived from material licensed
88fb65cergrimes * to the University of California by American Telephone and Telegraph
98fb65cergrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
108fb65cergrimes * the permission of UNIX System Laboratories, Inc.
118fb65cergrimes *
128fb65cergrimes * Redistribution and use in source and binary forms, with or without
138fb65cergrimes * modification, are permitted provided that the following conditions
148fb65cergrimes * are met:
158fb65cergrimes * 1. Redistributions of source code must retain the above copyright
168fb65cergrimes *    notice, this list of conditions and the following disclaimer.
178fb65cergrimes * 2. Redistributions in binary form must reproduce the above copyright
188fb65cergrimes *    notice, this list of conditions and the following disclaimer in the
198fb65cergrimes *    documentation and/or other materials provided with the distribution.
2000b67b1emaste * 3. Neither the name of the University nor the names of its contributors
218fb65cergrimes *    may be used to endorse or promote products derived from this software
228fb65cergrimes *    without specific prior written permission.
238fb65cergrimes *
248fb65cergrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
258fb65cergrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268fb65cergrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278fb65cergrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
288fb65cergrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
298fb65cergrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
308fb65cergrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
318fb65cergrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
328fb65cergrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
338fb65cergrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
348fb65cergrimes * SUCH DAMAGE.
358fb65cergrimes *
368fb65cergrimes *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
378fb65cergrimes */
388fb65cergrimes
393b8fff9obrien#include <sys/cdefs.h>
403b8fff9obrien__FBSDID("$FreeBSD$");
413b8fff9obrien
42aec8808ken#ifdef _KERNEL
43bc8317aphk#include "opt_ddb.h"
44da35e3ejb#include "opt_printf.h"
45aec8808ken#endif  /* _KERNEL */
46bc8317aphk
478fb65cergrimes#include <sys/param.h>
48aec8808ken#ifdef _KERNEL
498fb65cergrimes#include <sys/systm.h>
50a09da29tanimura#include <sys/lock.h>
5154e2d39marcel#include <sys/kdb.h>
52a09da29tanimura#include <sys/mutex.h>
53a09da29tanimura#include <sys/sx.h>
54d3d65c6phk#include <sys/kernel.h>
558fb65cergrimes#include <sys/msgbuf.h>
5636e7a51phk#include <sys/malloc.h>
5710d0d9crwatson#include <sys/priv.h>
588fb65cergrimes#include <sys/proc.h>
5906657e3mux#include <sys/stddef.h>
6095c1f2fphk#include <sys/sysctl.h>
618fb65cergrimes#include <sys/tty.h>
628fb65cergrimes#include <sys/syslog.h>
63ee871b6phk#include <sys/cons.h>
6404b71d6phk#include <sys/uio.h>
6538fa0aacem#else /* !_KERNEL */
6638fa0aacem#include <errno.h>
67aec8808ken#endif
687e4fc3bjkim#include <sys/ctype.h>
69aec8808ken#include <sys/sbuf.h>
708fb65cergrimes
71bc8317aphk#ifdef DDB
72bc8317aphk#include <ddb/ddb.h>
73bc8317aphk#endif
74bc8317aphk
758fb65cergrimes/*
768fb65cergrimes * Note that stdarg.h and the ANSI style va_start macro is used for both
778fb65cergrimes * ANSI and traditional C compilers.
788fb65cergrimes */
79f7a7b1emarcel#ifdef _KERNEL
808fb65cergrimes#include <machine/stdarg.h>
81f7a7b1emarcel#else
82f7a7b1emarcel#include <stdarg.h>
83dd0e3acscottl#endif
84dd0e3acscottl
85dd0e3acscottl/*
86dd0e3acscottl * This is needed for sbuf_putbuf() when compiled into userland.  Due to the
87dd0e3acscottl * shared nature of this file, it's the only place to put it.
88dd0e3acscottl */
89dd0e3acscottl#ifndef _KERNEL
900bc4396jkim#include <stdio.h>
91f7a7b1emarcel#endif
928fb65cergrimes
93aec8808ken#ifdef _KERNEL
94aec8808ken
958fb65cergrimes#define TOCONS	0x01
968fb65cergrimes#define TOTTY	0x02
978fb65cergrimes#define TOLOG	0x04
988fb65cergrimes
9949a30aapeter/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
100a79d749des#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
1018fb65cergrimes
1028ccd28aarchiestruct putchar_arg {
103dcb08e1archie	int	flags;
10404b71d6phk	int	pri;
105dcb08e1archie	struct	tty *tty;
106d2bd807jb	char	*p_bufr;
107d2bd807jb	size_t	n_bufr;
108d2bd807jb	char	*p_next;
109d2bd807jb	size_t	remain;
1108ccd28aarchie};
1118ccd28aarchie
1128ccd28aarchiestruct snprintf_arg {
113dcb08e1archie	char	*str;
114dcb08e1archie	size_t	remain;
1158ccd28aarchie};
1168ccd28aarchie
11704b71d6phkextern	int log_open;
11804b71d6phk
11904b71d6phkstatic void  msglogchar(int c, int pri);
1200febb6dkenstatic void  msglogstr(char *str, int pri, int filter_cr);
121357e37ealfredstatic void  putchar(int ch, void *arg);
1227e4fc3bjkimstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
123357e37ealfredstatic void  snprintf_func(int ch, void *arg);
1248fb65cergrimes
1253aecd7akevansstatic bool msgbufmapped;		/* Set when safe to use msgbuf */
12604b71d6phkint msgbuftrigger;
127d81660fbdestruct msgbuf *msgbufp;
1288fb65cergrimes
129d2718a6kevans#ifndef BOOT_TAG_SZ
130d2718a6kevans#define	BOOT_TAG_SZ	32
131d2718a6kevans#endif
132d2718a6kevans#ifndef BOOT_TAG
133d2718a6kevans/* Tag used to mark the start of a boot in dmesg */
134d2718a6kevans#define	BOOT_TAG	"---<<BOOT>>---"
135d2718a6kevans#endif
136d2718a6kevans
137d2718a6kevansstatic char current_boot_tag[BOOT_TAG_SZ + 1] = BOOT_TAG;
138d2718a6kevansSYSCTL_STRING(_kern, OID_AUTO, boot_tag, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
139d2718a6kevans    current_boot_tag, 0, "Tag added to dmesg at start of boot");
140d2718a6kevans
14135b126ehselaskystatic int log_console_output = 1;
14235b126ehselaskySYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RWTUN,
14335b126ehselasky    &log_console_output, 0, "Duplicate console output to the syslog");
144e57eac4green
1450febb6dken/*
1460febb6dken * See the comment in log_console() below for more explanation of this.
1470febb6dken */
14835b126ehselaskystatic int log_console_add_linefeed;
14935b126ehselaskySYSCTL_INT(_kern, OID_AUTO, log_console_add_linefeed, CTLFLAG_RWTUN,
15035b126ehselasky    &log_console_add_linefeed, 0, "log_console() adds extra newlines");
15135b126ehselasky
15235b126ehselaskystatic int always_console_output;
15335b126ehselaskySYSCTL_INT(_kern, OID_AUTO, always_console_output, CTLFLAG_RWTUN,
15435b126ehselasky    &always_console_output, 0, "Always output to console despite TIOCCONS");
1552eb82b9dwmalone
1568fb65cergrimes/*
1578fb65cergrimes * Warn that a system table is full.
1588fb65cergrimes */
1598fb65cergrimesvoid
16004b71d6phktablefull(const char *tab)
1618fb65cergrimes{
1628fb65cergrimes
1638fb65cergrimes	log(LOG_ERR, "%s: table is full\n", tab);
1648fb65cergrimes}
1658fb65cergrimes
1668fb65cergrimes/*
1678fb65cergrimes * Uprintf prints to the controlling terminal for the current process.
1688fb65cergrimes */
16949f6f0fdfrint
1708fb65cergrimesuprintf(const char *fmt, ...)
1718fb65cergrimes{
1728fb65cergrimes	va_list ap;
173c3e6222phk	struct putchar_arg pca;
1742078a09ed	struct proc *p;
1752078a09ed	struct thread *td;
176a09da29tanimura	int retval;
177a09da29tanimura
1782078a09ed	td = curthread;
1792078a09ed	if (TD_IS_IDLETHREAD(td))
180a09da29tanimura		return (0);
181a09da29tanimura
182cc3116aed	sx_slock(&proctree_lock);
1832078a09ed	p = td->td_proc;
184a09da29tanimura	PROC_LOCK(p);
185a09da29tanimura	if ((p->p_flag & P_CONTROLT) == 0) {
186a09da29tanimura		PROC_UNLOCK(p);
187b3080dakib		sx_sunlock(&proctree_lock);
188b3080dakib		return (0);
1898fb65cergrimes	}
190a09da29tanimura	SESS_LOCK(p->p_session);
191a09da29tanimura	pca.tty = p->p_session->s_ttyp;
192a09da29tanimura	SESS_UNLOCK(p->p_session);
193a09da29tanimura	PROC_UNLOCK(p);
1940106e15rwatson	if (pca.tty == NULL) {
195b3080dakib		sx_sunlock(&proctree_lock);
196b3080dakib		return (0);
1970106e15rwatson	}
198a09da29tanimura	pca.flags = TOTTY;
199048adb6ken	pca.p_bufr = NULL;
200a09da29tanimura	va_start(ap, fmt);
201cc3116aed	tty_lock(pca.tty);
202b3080dakib	sx_sunlock(&proctree_lock);
203a09da29tanimura	retval = kvprintf(fmt, putchar, &pca, 10, ap);
204cc3116aed	tty_unlock(pca.tty);
205a09da29tanimura	va_end(ap);
20695c1f2fphk	return (retval);
2078fb65cergrimes}
2088fb65cergrimes
2098fb65cergrimes/*
21024e0bcenp * tprintf and vtprintf print on the controlling terminal associated with the
21124e0bcenp * given session, possibly to the log as well.
2128fb65cergrimes */
2137101ba5phkvoid
2147101ba5phktprintf(struct proc *p, int pri, const char *fmt, ...)
2158fb65cergrimes{
21624e0bcenp	va_list ap;
21724e0bcenp
21824e0bcenp	va_start(ap, fmt);
21924e0bcenp	vtprintf(p, pri, fmt, ap);
22024e0bcenp	va_end(ap);
22124e0bcenp}
22224e0bcenp
22324e0bcenpvoid
22424e0bcenpvtprintf(struct proc *p, int pri, const char *fmt, va_list ap)
22524e0bcenp{
2268fb65cergrimes	struct tty *tp = NULL;
227872336ejhb	int flags = 0;
228c3e6222phk	struct putchar_arg pca;
229872336ejhb	struct session *sess = NULL;
2308fb65cergrimes
231cc3116aed	sx_slock(&proctree_lock);
23204b71d6phk	if (pri != -1)
2337101ba5phk		flags |= TOLOG;
234a09da29tanimura	if (p != NULL) {
235a09da29tanimura		PROC_LOCK(p);
236a09da29tanimura		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
237872336ejhb			sess = p->p_session;
238cc3116aed			sess_hold(sess);
239a09da29tanimura			PROC_UNLOCK(p);
240872336ejhb			tp = sess->s_ttyp;
241cc3116aed			if (tp != NULL && tty_checkoutq(tp))
242a09da29tanimura				flags |= TOTTY;
243a09da29tanimura			else
244a09da29tanimura				tp = NULL;
245a09da29tanimura		} else
246a09da29tanimura			PROC_UNLOCK(p);
2478fb65cergrimes	}
24804b71d6phk	pca.pri = pri;
249c3e6222phk	pca.tty = tp;
250c3e6222phk	pca.flags = flags;
251048adb6ken	pca.p_bufr = NULL;
252cc3116aed	if (pca.tty != NULL)
253cc3116aed		tty_lock(pca.tty);
254b3080dakib	sx_sunlock(&proctree_lock);
255145891dphk	kvprintf(fmt, putchar, &pca, 10, ap);
256cc3116aed	if (pca.tty != NULL)
257cc3116aed		tty_unlock(pca.tty);
258d6c8765phk	if (sess != NULL)
259cc3116aed		sess_release(sess);
26004b71d6phk	msgbuftrigger = 1;
2618fb65cergrimes}
2628fb65cergrimes
263fd2362bbdrewerystatic int
264fd2362bbdrewery_vprintf(int level, int flags, const char *fmt, va_list ap)
2658fb65cergrimes{
26604b71d6phk	struct putchar_arg pca;
267fd2362bbdrewery	int retval;
2680febb6dken#ifdef PRINTF_BUFR_SIZE
2690febb6dken	char bufr[PRINTF_BUFR_SIZE];
2700febb6dken#endif
2718fb65cergrimes
27255fe588cperciva	TSENTER();
27304b71d6phk	pca.tty = NULL;
27404b71d6phk	pca.pri = level;
275fd2362bbdrewery	pca.flags = flags;
2760febb6dken#ifdef PRINTF_BUFR_SIZE
2770febb6dken	pca.p_bufr = bufr;
2780febb6dken	pca.p_next = pca.p_bufr;
2790febb6dken	pca.n_bufr = sizeof(bufr);
2800febb6dken	pca.remain = sizeof(bufr);
2810febb6dken	*pca.p_next = '\0';
2820febb6dken#else
283fd2362bbdrewery	/* Don't buffer console output. */
284d2bd807jb	pca.p_bufr = NULL;
2850febb6dken#endif
286c3e6222phk
287fd2362bbdrewery	retval = kvprintf(fmt, putchar, &pca, 10, ap);
288c3e6222phk
2890febb6dken#ifdef PRINTF_BUFR_SIZE
2900febb6dken	/* Write any buffered console/log output: */
2910febb6dken	if (*pca.p_bufr != '\0') {
2920febb6dken		if (pca.flags & TOLOG)
2930febb6dken			msglogstr(pca.p_bufr, level, /*filter_cr*/1);
2940febb6dken
2950febb6dken		if (pca.flags & TOCONS)
2960febb6dken			cnputs(pca.p_bufr);
2970febb6dken	}
2980febb6dken#endif
299fd2362bbdrewery
30055fe588cperciva	TSEXIT();
301fd2362bbdrewery	return (retval);
302fd2362bbdrewery}
303fd2362bbdrewery
304fd2362bbdrewery/*
305fd2362bbdrewery * Log writes to the log buffer, and guarantees not to sleep (so can be
306fd2362bbdrewery * called by interrupt routines).  If there is no process reading the
307fd2362bbdrewery * log yet, it writes to the console also.
308fd2362bbdrewery */
309fd2362bbdreweryvoid
310fd2362bbdrewerylog(int level, const char *fmt, ...)
311fd2362bbdrewery{
312fd2362bbdrewery	va_list ap;
313fd2362bbdrewery
314fd2362bbdrewery	va_start(ap, fmt);
315afc7726markj	vlog(level, fmt, ap);
316fd2362bbdrewery	va_end(ap);
317afc7726markj}
318afc7726markj
319afc7726markjvoid
320afc7726markjvlog(int level, const char *fmt, va_list ap)
321afc7726markj{
322fd2362bbdrewery
323afc7726markj	(void)_vprintf(level, log_open ? TOLOG : TOCONS | TOLOG, fmt, ap);
324bfa5821phk	msgbuftrigger = 1;
3258fb65cergrimes}
3268fb65cergrimes
32704b71d6phk#define CONSCHUNK 128
3288fb65cergrimes
32904b71d6phkvoid
33004b71d6phklog_console(struct uio *uio)
33104b71d6phk{
3320febb6dken	int c, error, nl;
33304b71d6phk	char *consbuffer;
33404b71d6phk	int pri;
33504b71d6phk
3362eb82b9dwmalone	if (!log_console_output)
3372eb82b9dwmalone		return;
3382eb82b9dwmalone
33904b71d6phk	pri = LOG_INFO | LOG_CONSOLE;
340b9f13e4phk	uio = cloneuio(uio);
341b9f13e4phk	consbuffer = malloc(CONSCHUNK, M_TEMP, M_WAITOK);
34204b71d6phk
343c48b61aed	nl = 0;
34404b71d6phk	while (uio->uio_resid > 0) {
3450febb6dken		c = imin(uio->uio_resid, CONSCHUNK - 1);
34604b71d6phk		error = uiomove(consbuffer, c, uio);
34704b71d6phk		if (error != 0)
348a4c01edphk			break;
3490febb6dken		/* Make sure we're NUL-terminated */
3500febb6dken		consbuffer[c] = '\0';
3510febb6dken		if (consbuffer[c - 1] == '\n')
3520febb6dken			nl = 1;
3530febb6dken		else
3540febb6dken			nl = 0;
3550febb6dken		msglogstr(consbuffer, pri, /*filter_cr*/ 1);
3560febb6dken	}
3570febb6dken	/*
3580febb6dken	 * The previous behavior in log_console() is preserved when
3590febb6dken	 * log_console_add_linefeed is non-zero.  For that behavior, if an
3600febb6dken	 * individual console write came in that was not terminated with a
3610febb6dken	 * line feed, it would add a line feed.
3620febb6dken	 *
3630febb6dken	 * This results in different data in the message buffer than
3640febb6dken	 * appears on the system console (which doesn't add extra line feed
3650febb6dken	 * characters).
3660febb6dken	 *
3670febb6dken	 * A number of programs and rc scripts write a line feed, or a period
3680febb6dken	 * and a line feed when they have completed their operation.  On
3690febb6dken	 * the console, this looks seamless, but when displayed with
370