subr_log.c revision 111741
178556Sobrien/*
278556Sobrien * Copyright (c) 1982, 1986, 1993
378556Sobrien *	The Regents of the University of California.  All rights reserved.
478556Sobrien *
578556Sobrien * Redistribution and use in source and binary forms, with or without
678556Sobrien * modification, are permitted provided that the following conditions
7167974Sdelphij * are met:
8167974Sdelphij * 1. Redistributions of source code must retain the above copyright
9167974Sdelphij *    notice, this list of conditions and the following disclaimer.
1078556Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11177420Sdelphij *    notice, this list of conditions and the following disclaimer in the
12177420Sdelphij *    documentation and/or other materials provided with the distribution.
1378556Sobrien * 3. All advertising materials mentioning features or use of this software
14167974Sdelphij *    must display the following acknowledgement:
15167974Sdelphij *	This product includes software developed by the University of
1678556Sobrien *	California, Berkeley and its contributors.
17167974Sdelphij * 4. Neither the name of the University nor the names of its contributors
18167974Sdelphij *    may be used to endorse or promote products derived from this software
19167974Sdelphij *    without specific prior written permission.
2078556Sobrien *
2178556Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2278556Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2378556Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2478556Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2578556Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2678556Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2778556Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2878556Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2978556Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3078556Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3178556Sobrien * SUCH DAMAGE.
3278556Sobrien *
3378556Sobrien *	@(#)subr_log.c	8.1 (Berkeley) 6/10/93
3478556Sobrien * $FreeBSD: head/sys/kern/subr_log.c 111741 2003-03-02 15:50:23Z des $
3578556Sobrien */
3678556Sobrien
3778556Sobrien/*
3878556Sobrien * Error log buffer for kernel printf's.
39177420Sdelphij */
4078556Sobrien
4178556Sobrien#include <sys/param.h>
4278556Sobrien#include <sys/systm.h>
4378556Sobrien#include <sys/conf.h>
4478556Sobrien#include <sys/proc.h>
4578556Sobrien#include <sys/vnode.h>
4678556Sobrien#include <sys/filio.h>
4778556Sobrien#include <sys/ttycom.h>
4878556Sobrien#include <sys/msgbuf.h>
4978556Sobrien#include <sys/signalvar.h>
5078556Sobrien#include <sys/kernel.h>
5178556Sobrien#include <sys/poll.h>
5278556Sobrien#include <sys/filedesc.h>
5378556Sobrien#include <sys/sysctl.h>
5478556Sobrien
5578556Sobrien#define LOG_RDPRI	(PZERO + 1)
5678556Sobrien
57167974Sdelphij#define LOG_ASYNC	0x04
5878556Sobrien#define LOG_RDWAIT	0x08
5978556Sobrien
6078556Sobrienstatic	d_open_t	logopen;
61167974Sdelphijstatic	d_close_t	logclose;
6278556Sobrienstatic	d_read_t	logread;
6378556Sobrienstatic	d_ioctl_t	logioctl;
6478556Sobrienstatic	d_poll_t	logpoll;
6578556Sobrien
6678556Sobrienstatic	void logtimeout(void *arg);
6778556Sobrien
6878556Sobrien#define CDEV_MAJOR 7
6978556Sobrienstatic struct cdevsw log_cdevsw = {
7078556Sobrien	/* open */	logopen,
7178556Sobrien	/* close */	logclose,
72167974Sdelphij	/* read */	logread,
7378556Sobrien	/* write */	nowrite,
7478556Sobrien	/* ioctl */	logioctl,
7578556Sobrien	/* poll */	logpoll,
7678556Sobrien	/* mmap */	nommap,
7778556Sobrien	/* strategy */	nostrategy,
7878556Sobrien	/* name */	"log",
7978556Sobrien	/* maj */	CDEV_MAJOR,
8078556Sobrien	/* dump */	nodump,
8178556Sobrien	/* psize */	nopsize,
8278556Sobrien	/* flags */	0,
8378556Sobrien};
8478556Sobrien
85167974Sdelphijstatic struct logsoftc {
8678556Sobrien	int	sc_state;		/* see above for possibilities */
87167974Sdelphij	struct	selinfo sc_selp;	/* process waiting on select call */
8878556Sobrien	struct  sigio *sc_sigio;	/* information for async I/O */
8978556Sobrien	struct	callout sc_callout;	/* callout to wakeup syslog  */
9078556Sobrien} logsoftc;
91167974Sdelphij
92167974Sdelphijint	log_open;			/* also used in log() */
93167974Sdelphij
94167974Sdelphij/* Times per second to check for a pending syslog wakeup. */
95167974Sdelphijstatic int	log_wakeups_per_second = 5;
96167974SdelphijSYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW,
97167974Sdelphij    &log_wakeups_per_second, 0, "");
98167974Sdelphij
9978556Sobrien/*ARGSUSED*/
10078556Sobrienstatic	int
10178556Sobrienlogopen(dev_t dev, int flags, int mode, struct thread *td)
10278556Sobrien{
10378556Sobrien	if (log_open)
10478556Sobrien		return (EBUSY);
10578556Sobrien	log_open = 1;
10690067Ssobomax	callout_init(&logsoftc.sc_callout, 0);
10790067Ssobomax	fsetown(td->td_proc->p_pid, &logsoftc.sc_sigio);	/* signal process only */
10890067Ssobomax	callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second,
10990067Ssobomax	    logtimeout, NULL);
11090067Ssobomax	return (0);
11190067Ssobomax}
11290067Ssobomax
11378556Sobrien/*ARGSUSED*/
11478556Sobrienstatic	int
11578556Sobrienlogclose(dev_t dev, int flag, int mode, struct thread *td)
11678556Sobrien{
11778556Sobrien
11878556Sobrien	log_open = 0;
11978556Sobrien	callout_stop(&logsoftc.sc_callout);
12078556Sobrien	logsoftc.sc_state = 0;
12178556Sobrien	funsetown(&logsoftc.sc_sigio);
12278556Sobrien	return (0);
12378556Sobrien}
12478556Sobrien
12578556Sobrien/*ARGSUSED*/
12678556Sobrienstatic	int
12778556Sobrienlogread(dev_t dev, struct uio *uio, int flag)
12878556Sobrien{
12978556Sobrien	struct msgbuf *mbp = msgbufp;
13078556Sobrien	int error = 0, l, s;
13178556Sobrien
13278556Sobrien	s = splhigh();
13378556Sobrien	while (mbp->msg_bufr == mbp->msg_bufx) {
13478556Sobrien		if (flag & IO_NDELAY) {
13578556Sobrien			splx(s);
13678556Sobrien			return (EWOULDBLOCK);
13778556Sobrien		}
13878556Sobrien		logsoftc.sc_state |= LOG_RDWAIT;
13978556Sobrien		if ((error = tsleep(mbp, LOG_RDPRI | PCATCH, "klog", 0))) {
14078556Sobrien			splx(s);
14178556Sobrien			return (error);
14278556Sobrien		}
14378556Sobrien	}
14478556Sobrien	splx(s);
14578556Sobrien	logsoftc.sc_state &= ~LOG_RDWAIT;
14678556Sobrien
14778556Sobrien	while (uio->uio_resid > 0) {
14878556Sobrien		l = mbp->msg_bufx - mbp->msg_bufr;
14978556Sobrien		if (l < 0)
15078556Sobrien			l = mbp->msg_size - mbp->msg_bufr;
15178556Sobrien		l = imin(l, uio->uio_resid);
15278556Sobrien		if (l == 0)
15378556Sobrien			break;
15478556Sobrien		error = uiomove((char *)msgbufp->msg_ptr + mbp->msg_bufr,
15578556Sobrien		    l, uio);
15678556Sobrien		if (error)
15778556Sobrien			break;
15878556Sobrien		mbp->msg_bufr += l;
15978556Sobrien		if (mbp->msg_bufr >= mbp->msg_size)
16078556Sobrien			mbp->msg_bufr = 0;
16178556Sobrien	}
16278556Sobrien	return (error);
16378556Sobrien}
16478556Sobrien
16578556Sobrien/*ARGSUSED*/
16678556Sobrienstatic	int
16778556Sobrienlogpoll(dev_t dev, int events, struct thread *td)
16878556Sobrien{
16978556Sobrien	int s;
17078556Sobrien	int revents = 0;
17178556Sobrien
17278556Sobrien	s = splhigh();
17378556Sobrien
17478556Sobrien	if (events & (POLLIN | POLLRDNORM)) {
17578556Sobrien		if (msgbufp->msg_bufr != msgbufp->msg_bufx)
17678556Sobrien			revents |= events & (POLLIN | POLLRDNORM);
17778556Sobrien		else
17878556Sobrien			selrecord(td, &logsoftc.sc_selp);
17978556Sobrien	}
18078556Sobrien	splx(s);
18178556Sobrien	return (revents);
18278556Sobrien}
18378556Sobrien
18478556Sobrienstatic void
18578556Sobrienlogtimeout(void *arg)
18678556Sobrien{
18778556Sobrien
18878556Sobrien	if (!log_open)
18978556Sobrien		return;
19078556Sobrien	if (msgbuftrigger == 0) {
19178556Sobrien		callout_reset(&logsoftc.sc_callout,
19278556Sobrien		    hz / log_wakeups_per_second, logtimeout, NULL);
19378556Sobrien		return;
19478556Sobrien	}
19578556Sobrien	msgbuftrigger = 0;
19678556Sobrien	selwakeup(&logsoftc.sc_selp);
19778556Sobrien	if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL)
19878556Sobrien		pgsigio(&logsoftc.sc_sigio, SIGIO, 0);
19978556Sobrien	if (logsoftc.sc_state & LOG_RDWAIT) {
20078556Sobrien		wakeup((caddr_t)msgbufp);
20178556Sobrien		logsoftc.sc_state &= ~LOG_RDWAIT;
20278556Sobrien	}
20378556Sobrien	callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second,
20478556Sobrien	    logtimeout, NULL);
20578556Sobrien}
20678556Sobrien
20778556Sobrien/*ARGSUSED*/
20878556Sobrienstatic	int
20978556Sobrienlogioctl(dev_t dev, u_long com, caddr_t data, int flag, struct thread *td)
21078556Sobrien{
21178556Sobrien	int l, s;
21278556Sobrien
21378556Sobrien	switch (com) {
21478556Sobrien
21578556Sobrien	/* return number of characters immediately available */
21678556Sobrien	case FIONREAD:
21778556Sobrien		s = splhigh();
21878556Sobrien		l = msgbufp->msg_bufx - msgbufp->msg_bufr;
21978556Sobrien		splx(s);
22078556Sobrien		if (l < 0)
22178556Sobrien			l += msgbufp->msg_size;
22278556Sobrien		*(int *)data = l;
22378556Sobrien		break;
22478556Sobrien
22578556Sobrien	case FIONBIO:
22678556Sobrien		break;
22778556Sobrien
22878556Sobrien	case FIOASYNC:
22978556Sobrien		if (*(int *)data)
23078556Sobrien			logsoftc.sc_state |= LOG_ASYNC;
23178556Sobrien		else
23278556Sobrien			logsoftc.sc_state &= ~LOG_ASYNC;
23378556Sobrien		break;
23478556Sobrien
23578556Sobrien	case FIOSETOWN:
23678556Sobrien		return (fsetown(*(int *)data, &logsoftc.sc_sigio));
23778556Sobrien
23878556Sobrien	case FIOGETOWN:
23978556Sobrien		*(int *)data = fgetown(&logsoftc.sc_sigio);
24078556Sobrien		break;
24178556Sobrien
24278556Sobrien	/* This is deprecated, FIOSETOWN should be used instead. */
24378556Sobrien	case TIOCSPGRP:
24478556Sobrien		return (fsetown(-(*(int *)data), &logsoftc.sc_sigio));
24578556Sobrien
24678556Sobrien	/* This is deprecated, FIOGETOWN should be used instead */
24778556Sobrien	case TIOCGPGRP:
24878556Sobrien		*(int *)data = -fgetown(&logsoftc.sc_sigio);
24978556Sobrien		break;
25078556Sobrien
25178556Sobrien	default:
25278556Sobrien		return (ENOTTY);
25378556Sobrien	}
25478556Sobrien	return (0);
25578556Sobrien}
25678556Sobrien
25778556Sobrienstatic void
25878556Sobrienlog_drvinit(void *unused)
25978556Sobrien{
26078556Sobrien
26178556Sobrien	make_dev(&log_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "klog");
26278556Sobrien}
26378556Sobrien
26478556SobrienSYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,log_drvinit,NULL)
26578556Sobrien