subr_log.c revision 1.57
1/*	$OpenBSD: subr_log.c,v 1.57 2019/06/17 00:21:28 guenther Exp $	*/
2/*	$NetBSD: subr_log.c,v 1.11 1996/03/30 22:24:44 christos Exp $	*/
3
4/*
5 * Copyright (c) 1982, 1986, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)subr_log.c	8.1 (Berkeley) 6/10/93
33 */
34
35/*
36 * Error log buffer for kernel printf's.
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/proc.h>
42#include <sys/vnode.h>
43#include <sys/ioctl.h>
44#include <sys/msgbuf.h>
45#include <sys/file.h>
46#include <sys/tty.h>
47#include <sys/signalvar.h>
48#include <sys/syslog.h>
49#include <sys/poll.h>
50#include <sys/malloc.h>
51#include <sys/filedesc.h>
52#include <sys/socket.h>
53#include <sys/socketvar.h>
54#include <sys/fcntl.h>
55
56#ifdef KTRACE
57#include <sys/ktrace.h>
58#endif
59
60#include <sys/mount.h>
61#include <sys/syscallargs.h>
62
63#include <dev/cons.h>
64
65#define LOG_RDPRI	(PZERO + 1)
66
67#define LOG_ASYNC	0x04
68#define LOG_RDWAIT	0x08
69
70struct logsoftc {
71	int	sc_state;		/* see above for possibilities */
72	struct	selinfo sc_selp;	/* process waiting on select call */
73	int	sc_pgid;		/* process/group for async I/O */
74	uid_t	sc_siguid;		/* uid for process that set sc_pgid */
75	uid_t	sc_sigeuid;		/* euid for process that set sc_pgid */
76} logsoftc;
77
78int	log_open;			/* also used in log() */
79int	msgbufmapped;			/* is the message buffer mapped */
80struct	msgbuf *msgbufp;		/* the mapped buffer, itself. */
81struct	msgbuf *consbufp;		/* console message buffer. */
82struct	file *syslogf;
83
84void filt_logrdetach(struct knote *kn);
85int filt_logread(struct knote *kn, long hint);
86
87struct filterops logread_filtops =
88	{ 1, NULL, filt_logrdetach, filt_logread};
89
90int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg);
91
92void
93initmsgbuf(caddr_t buf, size_t bufsize)
94{
95	struct msgbuf *mbp;
96	long new_bufs;
97
98	/* Sanity-check the given size. */
99	if (bufsize < sizeof(struct msgbuf))
100		return;
101
102	mbp = msgbufp = (struct msgbuf *)buf;
103
104	new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc);
105	if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) ||
106	    (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) ||
107	    (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) {
108		/*
109		 * If the buffer magic number is wrong, has changed
110		 * size (which shouldn't happen often), or is
111		 * internally inconsistent, initialize it.
112		 */
113
114		memset(buf, 0, bufsize);
115		mbp->msg_magic = MSG_MAGIC;
116		mbp->msg_bufs = new_bufs;
117	}
118
119	/* Always start new buffer data on a new line. */
120	if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n')
121		msgbuf_putchar(msgbufp, '\n');
122
123	/* mark it as ready for use. */
124	msgbufmapped = 1;
125}
126
127void
128initconsbuf(void)
129{
130	long new_bufs;
131
132	/* Set up a buffer to collect /dev/console output */
133	consbufp = malloc(CONSBUFSIZE, M_TEMP, M_NOWAIT|M_ZERO);
134	if (consbufp) {
135		new_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc);
136		consbufp->msg_magic = MSG_MAGIC;
137		consbufp->msg_bufs = new_bufs;
138	}
139}
140
141void
142msgbuf_putchar(struct msgbuf *mbp, const char c)
143{
144	int s;
145
146	if (mbp->msg_magic != MSG_MAGIC)
147		/* Nothing we can do */
148		return;
149
150	s = splhigh();
151	mbp->msg_bufc[mbp->msg_bufx++] = c;
152	mbp->msg_bufl = lmin(mbp->msg_bufl+1, mbp->msg_bufs);
153	if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs)
154		mbp->msg_bufx = 0;
155	/* If the buffer is full, keep the most recent data. */
156	if (mbp->msg_bufr == mbp->msg_bufx) {
157		if (++mbp->msg_bufr >= mbp->msg_bufs)
158			mbp->msg_bufr = 0;
159		mbp->msg_bufd++;
160	}
161	splx(s);
162}
163
164int
165logopen(dev_t dev, int flags, int mode, struct proc *p)
166{
167	if (log_open)
168		return (EBUSY);
169	log_open = 1;
170	return (0);
171}
172
173int
174logclose(dev_t dev, int flag, int mode, struct proc *p)
175{
176	struct file *fp;
177
178	fp = syslogf;
179	syslogf = NULL;
180	if (fp)
181		FRELE(fp, p);
182	log_open = 0;
183	logsoftc.sc_state = 0;
184	return (0);
185}
186
187int
188logread(dev_t dev, struct uio *uio, int flag)
189{
190	struct msgbuf *mbp = msgbufp;
191	size_t l;
192	int s, error = 0;
193
194	s = splhigh();
195	while (mbp->msg_bufr == mbp->msg_bufx) {
196		if (flag & IO_NDELAY) {
197			error = EWOULDBLOCK;
198			goto out;
199		}
200		logsoftc.sc_state |= LOG_RDWAIT;
201		error = tsleep(mbp, LOG_RDPRI | PCATCH,
202			       "klog", 0);
203		if (error)
204			goto out;
205	}
206	logsoftc.sc_state &= ~LOG_RDWAIT;
207
208	if (mbp->msg_bufd > 0) {
209		char buf[64];
210
211		l = snprintf(buf, sizeof(buf),
212		    "<%d>klog: dropped %ld byte%s, message buffer full\n",
213		    LOG_KERN|LOG_WARNING, mbp->msg_bufd,
214                    mbp->msg_bufd == 1 ? "" : "s");
215		error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio);
216		if (error)
217			goto out;
218		mbp->msg_bufd = 0;
219	}
220
221	while (uio->uio_resid > 0) {
222		if (mbp->msg_bufx >= mbp->msg_bufr)
223			l = mbp->msg_bufx - mbp->msg_bufr;
224		else
225			l = mbp->msg_bufs - mbp->msg_bufr;
226		l = ulmin(l, uio->uio_resid);
227		if (l == 0)
228			break;
229		error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], l, uio);
230		if (error)
231			break;
232		mbp->msg_bufr += l;
233		if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs)
234			mbp->msg_bufr = 0;
235	}
236 out:
237	splx(s);
238	return (error);
239}
240
241int
242logpoll(dev_t dev, int events, struct proc *p)
243{
244	int s, revents = 0;
245
246	s = splhigh();
247	if (events & (POLLIN | POLLRDNORM)) {
248		if (msgbufp->msg_bufr != msgbufp->msg_bufx)
249			revents |= events & (POLLIN | POLLRDNORM);
250		else
251			selrecord(p, &logsoftc.sc_selp);
252	}
253	splx(s);
254	return (revents);
255}
256
257int
258logkqfilter(dev_t dev, struct knote *kn)
259{
260	struct klist *klist;
261	int s;
262
263	switch (kn->kn_filter) {
264	case EVFILT_READ:
265		klist = &logsoftc.sc_selp.si_note;
266		kn->kn_fop = &logread_filtops;
267		break;
268	default:
269		return (EINVAL);
270	}
271
272	kn->kn_hook = (void *)msgbufp;
273
274	s = splhigh();
275	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
276	splx(s);
277
278	return (0);
279}
280
281void
282filt_logrdetach(struct knote *kn)
283{
284	int s;
285
286	s = splhigh();
287	SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext);
288	splx(s);
289}
290
291int
292filt_logread(struct knote *kn, long hint)
293{
294	struct  msgbuf *p = (struct  msgbuf *)kn->kn_hook;
295	int s, event = 0;
296
297	s = splhigh();
298	kn->kn_data = (int)(p->msg_bufx - p->msg_bufr);
299	event = (p->msg_bufx != p->msg_bufr);
300	splx(s);
301	return (event);
302}
303
304void
305logwakeup(void)
306{
307	if (!log_open)
308		return;
309	selwakeup(&logsoftc.sc_selp);
310	if (logsoftc.sc_state & LOG_ASYNC)
311		csignal(logsoftc.sc_pgid, SIGIO,
312		    logsoftc.sc_siguid, logsoftc.sc_sigeuid);
313	if (logsoftc.sc_state & LOG_RDWAIT) {
314		wakeup(msgbufp);
315		logsoftc.sc_state &= ~LOG_RDWAIT;
316	}
317}
318
319int
320logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p)
321{
322	struct file *fp;
323	long l;
324	int error, s;
325
326	switch (com) {
327
328	/* return number of characters immediately available */
329	case FIONREAD:
330		s = splhigh();
331		l = msgbufp->msg_bufx - msgbufp->msg_bufr;
332		splx(s);
333		if (l < 0)
334			l += msgbufp->msg_bufs;
335		*(int *)data = l;
336		break;
337
338	case FIONBIO:
339		break;
340
341	case FIOASYNC:
342		if (*(int *)data)
343			logsoftc.sc_state |= LOG_ASYNC;
344		else
345			logsoftc.sc_state &= ~LOG_ASYNC;
346		break;
347
348	case TIOCSPGRP:
349		logsoftc.sc_pgid = *(int *)data;
350		logsoftc.sc_siguid = p->p_ucred->cr_ruid;
351		logsoftc.sc_sigeuid = p->p_ucred->cr_uid;
352		break;
353
354	case TIOCGPGRP:
355		*(int *)data = logsoftc.sc_pgid;
356		break;
357
358	case LIOCSFD:
359		if ((error = suser(p)) != 0)
360			return (error);
361		fp = syslogf;
362		if ((error = getsock(p, *(int *)data, &syslogf)) != 0)
363			return (error);
364		if (fp)
365			FRELE(fp, p);
366		break;
367
368	default:
369		return (ENOTTY);
370	}
371	return (0);
372}
373
374int
375sys_sendsyslog(struct proc *p, void *v, register_t *retval)
376{
377	struct sys_sendsyslog_args /* {
378		syscallarg(const char *) buf;
379		syscallarg(size_t) nbyte;
380		syscallarg(int) flags;
381	} */ *uap = v;
382	int error;
383	static int dropped_count, orig_error, orig_pid;
384
385	if (dropped_count) {
386		size_t l;
387		char buf[80];
388
389		l = snprintf(buf, sizeof(buf),
390		    "<%d>sendsyslog: dropped %d message%s, error %d, pid %d",
391		    LOG_KERN|LOG_WARNING, dropped_count,
392		    dropped_count == 1 ? "" : "s", orig_error, orig_pid);
393		error = dosendsyslog(p, buf, ulmin(l, sizeof(buf) - 1),
394		    0, UIO_SYSSPACE);
395		if (error == 0) {
396			dropped_count = 0;
397			orig_error = 0;
398			orig_pid = 0;
399		}
400	}
401	error = dosendsyslog(p, SCARG(uap, buf), SCARG(uap, nbyte),
402	    SCARG(uap, flags), UIO_USERSPACE);
403	if (error) {
404		dropped_count++;
405		orig_error = error;
406		orig_pid = p->p_p->ps_pid;
407	}
408	return (error);
409}
410
411int
412dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags,
413    enum uio_seg sflg)
414{
415#ifdef KTRACE
416	struct iovec ktriov;
417#endif
418	struct file *fp;
419	char pri[6], *kbuf;
420	struct iovec aiov;
421	struct uio auio;
422	size_t i, len;
423	int error;
424
425	if (nbyte > LOG_MAXLINE)
426		nbyte = LOG_MAXLINE;
427
428	/* Global variable syslogf may change during sleep, use local copy. */
429	fp = syslogf;
430	if (fp)
431		FREF(fp);
432	else if (!ISSET(flags, LOG_CONS))
433		return (ENOTCONN);
434	else {
435		/*
436		 * Strip off syslog priority when logging to console.
437		 * LOG_PRIMASK | LOG_FACMASK is 0x03ff, so at most 4
438		 * decimal digits may appear in priority as <1023>.
439		 */
440		len = MIN(nbyte, sizeof(pri));
441		if (sflg == UIO_USERSPACE) {
442			if ((error = copyin(buf, pri, len)))
443				return (error);
444		} else
445			memcpy(pri, buf, len);
446		if (0 < len && pri[0] == '<') {
447			for (i = 1; i < len; i++) {
448				if (pri[i] < '0' || pri[i] > '9')
449					break;
450			}
451			if (i < len && pri[i] == '>') {
452				i++;
453				/* There must be at least one digit <0>. */
454				if (i >= 3) {
455					buf += i;
456					nbyte -= i;
457				}
458			}
459		}
460	}
461
462	aiov.iov_base = (char *)buf;
463	aiov.iov_len = nbyte;
464	auio.uio_iov = &aiov;
465	auio.uio_iovcnt = 1;
466	auio.uio_segflg = sflg;
467	auio.uio_rw = UIO_WRITE;
468	auio.uio_procp = p;
469	auio.uio_offset = 0;
470	auio.uio_resid = aiov.iov_len;
471#ifdef KTRACE
472	if (sflg == UIO_USERSPACE && KTRPOINT(p, KTR_GENIO))
473		ktriov = aiov;
474	else
475		ktriov.iov_len = 0;
476#endif
477
478	len = auio.uio_resid;
479	if (fp) {
480		int flags = (fp->f_flag & FNONBLOCK) ? MSG_DONTWAIT : 0;
481		error = sosend(fp->f_data, NULL, &auio, NULL, NULL, flags);
482		if (error == 0)
483			len -= auio.uio_resid;
484	} else if (constty || cn_devvp) {
485		error = cnwrite(0, &auio, 0);
486		if (error == 0)
487			len -= auio.uio_resid;
488		aiov.iov_base = "\r\n";
489		aiov.iov_len = 2;
490		auio.uio_iov = &aiov;
491		auio.uio_iovcnt = 1;
492		auio.uio_segflg = UIO_SYSSPACE;
493		auio.uio_rw = UIO_WRITE;
494		auio.uio_procp = p;
495		auio.uio_offset = 0;
496		auio.uio_resid = aiov.iov_len;
497		cnwrite(0, &auio, 0);
498	} else {
499		/* XXX console redirection breaks down... */
500		if (sflg == UIO_USERSPACE) {
501			kbuf = malloc(len, M_TEMP, M_WAITOK);
502			error = copyin(aiov.iov_base, kbuf, len);
503		} else {
504			kbuf = aiov.iov_base;
505			error = 0;
506		}
507		if (error == 0)
508			for (i = 0; i < len; i++) {
509				if (kbuf[i] == '\0')
510					break;
511				cnputc(kbuf[i]);
512				auio.uio_resid--;
513			}
514		if (sflg == UIO_USERSPACE)
515			free(kbuf, M_TEMP, len);
516		if (error == 0)
517			len -= auio.uio_resid;
518		cnputc('\n');
519	}
520
521#ifdef KTRACE
522	if (error == 0 && ktriov.iov_len != 0)
523		ktrgenio(p, -1, UIO_WRITE, &ktriov, len);
524#endif
525	if (fp)
526		FRELE(fp, p);
527	else
528		error = ENOTCONN;
529	return (error);
530}
531