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