subr_log.c revision 77057
1193323Sed/* 2193323Sed * Copyright (c) 1982, 1986, 1993 3193323Sed * The Regents of the University of California. All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 3. All advertising materials mentioning features or use of this software 14193323Sed * must display the following acknowledgement: 15193323Sed * This product includes software developed by the University of 16193323Sed * California, Berkeley and its contributors. 17193323Sed * 4. Neither the name of the University nor the names of its contributors 18193323Sed * may be used to endorse or promote products derived from this software 19193323Sed * without specific prior written permission. 20193323Sed * 21193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26198892Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31193323Sed * SUCH DAMAGE. 32193323Sed * 33198892Srdivacky * @(#)subr_log.c 8.1 (Berkeley) 6/10/93 34193323Sed * $FreeBSD: head/sys/kern/subr_log.c 77057 2001-05-23 19:02:50Z phk $ 35193323Sed */ 36193323Sed 37193323Sed/* 38193323Sed * Error log buffer for kernel printf's. 39193323Sed */ 40193323Sed 41193323Sed#include <sys/param.h> 42193323Sed#include <sys/systm.h> 43193323Sed#include <sys/conf.h> 44193323Sed#include <sys/proc.h> 45193323Sed#include <sys/vnode.h> 46193323Sed#include <sys/filio.h> 47193323Sed#include <sys/ttycom.h> 48193323Sed#include <sys/msgbuf.h> 49193323Sed#include <sys/signalvar.h> 50193323Sed#include <sys/kernel.h> 51193323Sed#include <sys/poll.h> 52193323Sed#include <sys/filedesc.h> 53193323Sed#include <sys/sysctl.h> 54198892Srdivacky 55193323Sed#define LOG_RDPRI (PZERO + 1) 56193323Sed 57193323Sed#define LOG_ASYNC 0x04 58206083Srdivacky#define LOG_RDWAIT 0x08 59193323Sed 60193323Sedstatic d_open_t logopen; 61193323Sedstatic d_close_t logclose; 62193323Sedstatic d_read_t logread; 63198090Srdivackystatic d_ioctl_t logioctl; 64193323Sedstatic d_poll_t logpoll; 65193323Sed 66198090Srdivackystatic void logtimeout(void *arg); 67198090Srdivacky 68193323Sed#define CDEV_MAJOR 7 69193323Sedstatic struct cdevsw log_cdevsw = { 70193323Sed /* open */ logopen, 71193323Sed /* close */ logclose, 72193323Sed /* read */ logread, 73204642Srdivacky /* write */ nowrite, 74204642Srdivacky /* ioctl */ logioctl, 75204642Srdivacky /* poll */ logpoll, 76204642Srdivacky /* mmap */ nommap, 77204642Srdivacky /* strategy */ nostrategy, 78204642Srdivacky /* name */ "log", 79204642Srdivacky /* maj */ CDEV_MAJOR, 80204642Srdivacky /* dump */ nodump, 81204642Srdivacky /* psize */ nopsize, 82193323Sed /* flags */ 0, 83193323Sed}; 84193323Sed 85193323Sedstatic struct logsoftc { 86193323Sed int sc_state; /* see above for possibilities */ 87193323Sed struct selinfo sc_selp; /* process waiting on select call */ 88193323Sed struct sigio *sc_sigio; /* information for async I/O */ 89193323Sed struct callout sc_callout; /* callout to wakeup syslog */ 90193323Sed} logsoftc; 91193323Sed 92193323Sedint log_open; /* also used in log() */ 93193323Sed 94193323Sed/* Times per second to check for a pending syslog wakeup. */ 95193323Sedstatic int log_wakeups_per_second = 5; 96193323SedSYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW, 97193323Sed &log_wakeups_per_second, 0, ""); 98193323Sed 99193323Sed/*ARGSUSED*/ 100193323Sedstatic int 101193323Sedlogopen(dev_t dev, int flags, int mode, struct proc *p) 102193323Sed{ 103193323Sed if (log_open) 104193323Sed return (EBUSY); 105193323Sed log_open = 1; 106193323Sed callout_init(&logsoftc.sc_callout, 0); 107193323Sed fsetown(p->p_pid, &logsoftc.sc_sigio); /* signal process only */ 108193323Sed callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 109193323Sed logtimeout, NULL); 110193323Sed return (0); 111193323Sed} 112198892Srdivacky 113193323Sed/*ARGSUSED*/ 114207618Srdivackystatic int 115207618Srdivackylogclose(dev_t dev, int flag, int mode, struct proc *p) 116207618Srdivacky{ 117207618Srdivacky 118207618Srdivacky log_open = 0; 119207618Srdivacky callout_stop(&logsoftc.sc_callout); 120193323Sed logsoftc.sc_state = 0; 121193323Sed funsetown(logsoftc.sc_sigio); 122193323Sed return (0); 123193323Sed} 124193323Sed 125198892Srdivacky/*ARGSUSED*/ 126193323Sedstatic int 127193323Sedlogread(dev_t dev, struct uio *uio, int flag) 128200581Srdivacky{ 129200581Srdivacky struct msgbuf *mbp = msgbufp; 130200581Srdivacky long l; 131200581Srdivacky int s; 132200581Srdivacky int error = 0; 133200581Srdivacky 134200581Srdivacky s = splhigh(); 135193323Sed while (mbp->msg_bufr == mbp->msg_bufx) { 136205218Srdivacky if (flag & IO_NDELAY) { 137205218Srdivacky splx(s); 138205218Srdivacky return (EWOULDBLOCK); 139205218Srdivacky } 140205218Srdivacky logsoftc.sc_state |= LOG_RDWAIT; 141193323Sed if ((error = tsleep((caddr_t)mbp, LOG_RDPRI | PCATCH, 142193323Sed "klog", 0))) { 143193323Sed splx(s); 144193323Sed return (error); 145193323Sed } 146193323Sed } 147193323Sed splx(s); 148193323Sed logsoftc.sc_state &= ~LOG_RDWAIT; 149193323Sed 150193323Sed while (uio->uio_resid > 0) { 151193323Sed l = mbp->msg_bufx - mbp->msg_bufr; 152193323Sed if (l < 0) 153193323Sed l = mbp->msg_size - mbp->msg_bufr; 154193323Sed l = min(l, uio->uio_resid); 155193323Sed if (l == 0) 156193323Sed break; 157198090Srdivacky error = uiomove((caddr_t)msgbufp->msg_ptr + mbp->msg_bufr, 158193323Sed (int)l, uio); 159193323Sed if (error) 160193323Sed break; 161193323Sed mbp->msg_bufr += l; 162193323Sed if (mbp->msg_bufr >= mbp->msg_size) 163193323Sed mbp->msg_bufr = 0; 164193323Sed } 165193323Sed return (error); 166193323Sed} 167198892Srdivacky 168198892Srdivacky/*ARGSUSED*/ 169198892Srdivackystatic int 170198892Srdivackylogpoll(dev_t dev, int events, struct proc *p) 171198892Srdivacky{ 172198892Srdivacky int s; 173198892Srdivacky int revents = 0; 174198892Srdivacky 175193323Sed s = splhigh(); 176193323Sed 177198892Srdivacky if (events & (POLLIN | POLLRDNORM)) { 178198892Srdivacky if (msgbufp->msg_bufr != msgbufp->msg_bufx) 179193323Sed revents |= events & (POLLIN | POLLRDNORM); 180193323Sed else 181198892Srdivacky selrecord(p, &logsoftc.sc_selp); 182198892Srdivacky } 183198892Srdivacky splx(s); 184198892Srdivacky return (revents); 185198892Srdivacky} 186198892Srdivacky 187198892Srdivackystatic void 188198892Srdivackylogtimeout(void *arg) 189198892Srdivacky{ 190198892Srdivacky 191198892Srdivacky if (!log_open) 192198892Srdivacky return; 193198892Srdivacky if (msgbuftrigger == 0) { 194198892Srdivacky callout_reset(&logsoftc.sc_callout, 195198892Srdivacky hz / log_wakeups_per_second, logtimeout, NULL); 196198892Srdivacky return; 197198892Srdivacky } 198198892Srdivacky msgbuftrigger = 0; 199198892Srdivacky selwakeup(&logsoftc.sc_selp); 200198892Srdivacky if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL) 201198892Srdivacky pgsigio(logsoftc.sc_sigio, SIGIO, 0); 202198892Srdivacky if (logsoftc.sc_state & LOG_RDWAIT) { 203198892Srdivacky wakeup((caddr_t)msgbufp); 204198892Srdivacky logsoftc.sc_state &= ~LOG_RDWAIT; 205200581Srdivacky } 206200581Srdivacky callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 207200581Srdivacky logtimeout, NULL); 208200581Srdivacky} 209199481Srdivacky 210199481Srdivacky/*ARGSUSED*/ 211198892Srdivackystatic int 212198892Srdivackylogioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 213193323Sed{ 214198892Srdivacky long l; 215193323Sed int s; 216193323Sed 217193323Sed switch (com) { 218198892Srdivacky 219193323Sed /* return number of characters immediately available */ 220193323Sed case FIONREAD: 221198892Srdivacky s = splhigh(); 222198892Srdivacky l = msgbufp->msg_bufx - msgbufp->msg_bufr; 223198892Srdivacky splx(s); 224198892Srdivacky if (l < 0) 225198892Srdivacky l += msgbufp->msg_size; 226198892Srdivacky *(int *)data = l; 227199481Srdivacky break; 228198892Srdivacky 229198892Srdivacky case FIONBIO: 230206083Srdivacky break; 231193323Sed 232193323Sed case FIOASYNC: 233193323Sed if (*(int *)data) 234193323Sed logsoftc.sc_state |= LOG_ASYNC; 235193323Sed else 236193323Sed logsoftc.sc_state &= ~LOG_ASYNC; 237193323Sed break; 238193323Sed 239193323Sed case FIOSETOWN: 240193323Sed return (fsetown(*(int *)data, &logsoftc.sc_sigio)); 241193323Sed 242193323Sed case FIOGETOWN: 243198090Srdivacky *(int *)data = fgetown(logsoftc.sc_sigio); 244193323Sed break; 245193323Sed 246193323Sed /* This is deprecated, FIOSETOWN should be used instead. */ 247193323Sed case TIOCSPGRP: 248193323Sed return (fsetown(-(*(int *)data), &logsoftc.sc_sigio)); 249193323Sed 250193323Sed /* This is deprecated, FIOGETOWN should be used instead */ 251193323Sed case TIOCGPGRP: 252193323Sed *(int *)data = -fgetown(logsoftc.sc_sigio); 253193323Sed break; 254193323Sed 255193323Sed default: 256193323Sed return (ENOTTY); 257193323Sed } 258193323Sed return (0); 259193323Sed} 260193323Sed 261193323Sedstatic void 262193323Sedlog_drvinit(void *unused) 263193323Sed{ 264193323Sed 265193323Sed make_dev(&log_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "klog"); 266193323Sed} 267193323Sed 268193323SedSYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,log_drvinit,NULL) 269193323Sed