1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)subr_log.c 8.1 (Berkeley) 6/10/93 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36df8bae1dSRodney W. Grimes /* 37df8bae1dSRodney W. Grimes * Error log buffer for kernel printf's. 38df8bae1dSRodney W. Grimes */ 39df8bae1dSRodney W. Grimes 40677b542eSDavid E. O'Brien #include <sys/cdefs.h> 41677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 42677b542eSDavid E. O'Brien 43df8bae1dSRodney W. Grimes #include <sys/param.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 4598d93822SBruce Evans #include <sys/conf.h> 46df8bae1dSRodney W. Grimes #include <sys/proc.h> 47df8bae1dSRodney W. Grimes #include <sys/vnode.h> 4820982410SBruce Evans #include <sys/filio.h> 4920982410SBruce Evans #include <sys/ttycom.h> 50df8bae1dSRodney W. Grimes #include <sys/msgbuf.h> 51797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 5253ac6efbSJulian Elischer #include <sys/kernel.h> 531514b90fSPeter Wemm #include <sys/poll.h> 54831d27a9SDon Lewis #include <sys/filedesc.h> 55a9b13707SJohn Baldwin #include <sys/sysctl.h> 5653ac6efbSJulian Elischer 57df8bae1dSRodney W. Grimes #define LOG_RDPRI (PZERO + 1) 58df8bae1dSRodney W. Grimes 59df8bae1dSRodney W. Grimes #define LOG_ASYNC 0x04 60df8bae1dSRodney W. Grimes #define LOG_RDWAIT 0x08 61df8bae1dSRodney W. Grimes 6287f6c662SJulian Elischer static d_open_t logopen; 6387f6c662SJulian Elischer static d_close_t logclose; 6487f6c662SJulian Elischer static d_read_t logread; 6587f6c662SJulian Elischer static d_ioctl_t logioctl; 661514b90fSPeter Wemm static d_poll_t logpoll; 6787f6c662SJulian Elischer 68a9b13707SJohn Baldwin static void logtimeout(void *arg); 69a9b13707SJohn Baldwin 7087f6c662SJulian Elischer #define CDEV_MAJOR 7 714e2f199eSPoul-Henning Kamp static struct cdevsw log_cdevsw = { 727ac40f5fSPoul-Henning Kamp .d_open = logopen, 737ac40f5fSPoul-Henning Kamp .d_close = logclose, 747ac40f5fSPoul-Henning Kamp .d_read = logread, 757ac40f5fSPoul-Henning Kamp .d_ioctl = logioctl, 767ac40f5fSPoul-Henning Kamp .d_poll = logpoll, 777ac40f5fSPoul-Henning Kamp .d_name = "log", 787ac40f5fSPoul-Henning Kamp .d_maj = CDEV_MAJOR, 794e2f199eSPoul-Henning Kamp }; 8087f6c662SJulian Elischer 8187b6de2bSPoul-Henning Kamp static struct logsoftc { 82df8bae1dSRodney W. Grimes int sc_state; /* see above for possibilities */ 83df8bae1dSRodney W. Grimes struct selinfo sc_selp; /* process waiting on select call */ 8462d6ce3aSDon Lewis struct sigio *sc_sigio; /* information for async I/O */ 85a9b13707SJohn Baldwin struct callout sc_callout; /* callout to wakeup syslog */ 86df8bae1dSRodney W. Grimes } logsoftc; 87df8bae1dSRodney W. Grimes 88df8bae1dSRodney W. Grimes int log_open; /* also used in log() */ 89df8bae1dSRodney W. Grimes 90a9b13707SJohn Baldwin /* Times per second to check for a pending syslog wakeup. */ 91a9b13707SJohn Baldwin static int log_wakeups_per_second = 5; 92a9b13707SJohn Baldwin SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW, 93a9b13707SJohn Baldwin &log_wakeups_per_second, 0, ""); 94a9b13707SJohn Baldwin 95df8bae1dSRodney W. Grimes /*ARGSUSED*/ 9687f6c662SJulian Elischer static int 97b40ce416SJulian Elischer logopen(dev_t dev, int flags, int mode, struct thread *td) 98df8bae1dSRodney W. Grimes { 99df8bae1dSRodney W. Grimes if (log_open) 100df8bae1dSRodney W. Grimes return (EBUSY); 101df8bae1dSRodney W. Grimes log_open = 1; 102a9b13707SJohn Baldwin callout_init(&logsoftc.sc_callout, 0); 103b40ce416SJulian Elischer fsetown(td->td_proc->p_pid, &logsoftc.sc_sigio); /* signal process only */ 104b2b417bbSBosko Milekic if (log_wakeups_per_second < 1) { 105b2b417bbSBosko Milekic printf("syslog wakeup is less than one. Adjusting to 1.\n"); 106b2b417bbSBosko Milekic log_wakeups_per_second = 1; 107b2b417bbSBosko Milekic } 108a9b13707SJohn Baldwin callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 109a9b13707SJohn Baldwin logtimeout, NULL); 110df8bae1dSRodney W. Grimes return (0); 111df8bae1dSRodney W. Grimes } 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes /*ARGSUSED*/ 11487f6c662SJulian Elischer static int 115b40ce416SJulian Elischer logclose(dev_t dev, int flag, int mode, struct thread *td) 116df8bae1dSRodney W. Grimes { 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes log_open = 0; 1194787f91dSPoul-Henning Kamp callout_stop(&logsoftc.sc_callout); 120df8bae1dSRodney W. Grimes logsoftc.sc_state = 0; 121e649887bSAlfred Perlstein funsetown(&logsoftc.sc_sigio); 122df8bae1dSRodney W. Grimes return (0); 123df8bae1dSRodney W. Grimes } 124df8bae1dSRodney W. Grimes 125df8bae1dSRodney W. Grimes /*ARGSUSED*/ 12687f6c662SJulian Elischer static int 12706b6617eSPoul-Henning Kamp logread(dev_t dev, struct uio *uio, int flag) 128df8bae1dSRodney W. Grimes { 12906b6617eSPoul-Henning Kamp struct msgbuf *mbp = msgbufp; 13001ee4395SThomas Moestl int error = 0, l, s; 131df8bae1dSRodney W. Grimes 132df8bae1dSRodney W. Grimes s = splhigh(); 133df8bae1dSRodney W. Grimes while (mbp->msg_bufr == mbp->msg_bufx) { 134df8bae1dSRodney W. Grimes if (flag & IO_NDELAY) { 135df8bae1dSRodney W. Grimes splx(s); 136df8bae1dSRodney W. Grimes return (EWOULDBLOCK); 137df8bae1dSRodney W. Grimes } 138df8bae1dSRodney W. Grimes logsoftc.sc_state |= LOG_RDWAIT; 13901609114SAlfred Perlstein if ((error = tsleep(mbp, LOG_RDPRI | PCATCH, "klog", 0))) { 140df8bae1dSRodney W. Grimes splx(s); 141df8bae1dSRodney W. Grimes return (error); 142df8bae1dSRodney W. Grimes } 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes splx(s); 145df8bae1dSRodney W. Grimes logsoftc.sc_state &= ~LOG_RDWAIT; 146df8bae1dSRodney W. Grimes 147df8bae1dSRodney W. Grimes while (uio->uio_resid > 0) { 14801ee4395SThomas Moestl l = mbp->msg_bufx - mbp->msg_bufr; 149df8bae1dSRodney W. Grimes if (l < 0) 15058067a99SPoul-Henning Kamp l = mbp->msg_size - mbp->msg_bufr; 15101ee4395SThomas Moestl l = imin(l, uio->uio_resid); 152df8bae1dSRodney W. Grimes if (l == 0) 153df8bae1dSRodney W. Grimes break; 154c9524588SDag-Erling Smørgrav error = uiomove((char *)msgbufp->msg_ptr + mbp->msg_bufr, 15501ee4395SThomas Moestl l, uio); 156df8bae1dSRodney W. Grimes if (error) 157df8bae1dSRodney W. Grimes break; 158df8bae1dSRodney W. Grimes mbp->msg_bufr += l; 15958067a99SPoul-Henning Kamp if (mbp->msg_bufr >= mbp->msg_size) 160df8bae1dSRodney W. Grimes mbp->msg_bufr = 0; 161df8bae1dSRodney W. Grimes } 162df8bae1dSRodney W. Grimes return (error); 163df8bae1dSRodney W. Grimes } 164df8bae1dSRodney W. Grimes 165df8bae1dSRodney W. Grimes /*ARGSUSED*/ 16687f6c662SJulian Elischer static int 167b40ce416SJulian Elischer logpoll(dev_t dev, int events, struct thread *td) 168df8bae1dSRodney W. Grimes { 1691514b90fSPeter Wemm int s; 1701514b90fSPeter Wemm int revents = 0; 171df8bae1dSRodney W. Grimes 1721514b90fSPeter Wemm s = splhigh(); 173df8bae1dSRodney W. Grimes 174dfd5dee1SPeter Wemm if (events & (POLLIN | POLLRDNORM)) { 1751514b90fSPeter Wemm if (msgbufp->msg_bufr != msgbufp->msg_bufx) 1761514b90fSPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 1771514b90fSPeter Wemm else 178ed01445dSJohn Baldwin selrecord(td, &logsoftc.sc_selp); 179dfd5dee1SPeter Wemm } 180df8bae1dSRodney W. Grimes splx(s); 1811514b90fSPeter Wemm return (revents); 182df8bae1dSRodney W. Grimes } 183df8bae1dSRodney W. Grimes 184a9b13707SJohn Baldwin static void 185a9b13707SJohn Baldwin logtimeout(void *arg) 186a9b13707SJohn Baldwin { 187a9b13707SJohn Baldwin 188df8bae1dSRodney W. Grimes if (!log_open) 189df8bae1dSRodney W. Grimes return; 190b2b417bbSBosko Milekic if (log_wakeups_per_second < 1) { 191b2b417bbSBosko Milekic printf("syslog wakeup is less than one. Adjusting to 1.\n"); 192b2b417bbSBosko Milekic log_wakeups_per_second = 1; 193b2b417bbSBosko Milekic } 1944787f91dSPoul-Henning Kamp if (msgbuftrigger == 0) { 1954787f91dSPoul-Henning Kamp callout_reset(&logsoftc.sc_callout, 1964787f91dSPoul-Henning Kamp hz / log_wakeups_per_second, logtimeout, NULL); 1974787f91dSPoul-Henning Kamp return; 1984787f91dSPoul-Henning Kamp } 1994787f91dSPoul-Henning Kamp msgbuftrigger = 0; 200df8bae1dSRodney W. Grimes selwakeup(&logsoftc.sc_selp); 201831d27a9SDon Lewis if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL) 202f1320723SAlfred Perlstein pgsigio(&logsoftc.sc_sigio, SIGIO, 0); 203df8bae1dSRodney W. Grimes if (logsoftc.sc_state & LOG_RDWAIT) { 204521f364bSDag-Erling Smørgrav wakeup(msgbufp); 205df8bae1dSRodney W. Grimes logsoftc.sc_state &= ~LOG_RDWAIT; 206df8bae1dSRodney W. Grimes } 207a9b13707SJohn Baldwin callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 208a9b13707SJohn Baldwin logtimeout, NULL); 209df8bae1dSRodney W. Grimes } 210df8bae1dSRodney W. Grimes 211df8bae1dSRodney W. Grimes /*ARGSUSED*/ 21287f6c662SJulian Elischer static int 213b40ce416SJulian Elischer logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct thread *td) 214df8bae1dSRodney W. Grimes { 21501ee4395SThomas Moestl int l, s; 216df8bae1dSRodney W. Grimes 217df8bae1dSRodney W. Grimes switch (com) { 218df8bae1dSRodney W. Grimes 219df8bae1dSRodney W. Grimes /* return number of characters immediately available */ 220df8bae1dSRodney W. Grimes case FIONREAD: 221df8bae1dSRodney W. Grimes s = splhigh(); 22201ee4395SThomas Moestl l = msgbufp->msg_bufx - msgbufp->msg_bufr; 223df8bae1dSRodney W. Grimes splx(s); 224df8bae1dSRodney W. Grimes if (l < 0) 22558067a99SPoul-Henning Kamp l += msgbufp->msg_size; 226df8bae1dSRodney W. Grimes *(int *)data = l; 227df8bae1dSRodney W. Grimes break; 228df8bae1dSRodney W. Grimes 229df8bae1dSRodney W. Grimes case FIONBIO: 230df8bae1dSRodney W. Grimes break; 231df8bae1dSRodney W. Grimes 232df8bae1dSRodney W. Grimes case FIOASYNC: 233df8bae1dSRodney W. Grimes if (*(int *)data) 234df8bae1dSRodney W. Grimes logsoftc.sc_state |= LOG_ASYNC; 235df8bae1dSRodney W. Grimes else 236df8bae1dSRodney W. Grimes logsoftc.sc_state &= ~LOG_ASYNC; 237df8bae1dSRodney W. Grimes break; 238df8bae1dSRodney W. Grimes 239831d27a9SDon Lewis case FIOSETOWN: 240831d27a9SDon Lewis return (fsetown(*(int *)data, &logsoftc.sc_sigio)); 241831d27a9SDon Lewis 242831d27a9SDon Lewis case FIOGETOWN: 24391e97a82SDon Lewis *(int *)data = fgetown(&logsoftc.sc_sigio); 244df8bae1dSRodney W. Grimes break; 245df8bae1dSRodney W. Grimes 246831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 247831d27a9SDon Lewis case TIOCSPGRP: 248831d27a9SDon Lewis return (fsetown(-(*(int *)data), &logsoftc.sc_sigio)); 249831d27a9SDon Lewis 250831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead */ 251df8bae1dSRodney W. Grimes case TIOCGPGRP: 25291e97a82SDon Lewis *(int *)data = -fgetown(&logsoftc.sc_sigio); 253df8bae1dSRodney W. Grimes break; 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes default: 256bcac5617SJordan K. Hubbard return (ENOTTY); 257df8bae1dSRodney W. Grimes } 258df8bae1dSRodney W. Grimes return (0); 259df8bae1dSRodney W. Grimes } 26053ac6efbSJulian Elischer 26187f6c662SJulian Elischer static void 26206b6617eSPoul-Henning Kamp log_drvinit(void *unused) 26353ac6efbSJulian Elischer { 26406b6617eSPoul-Henning Kamp 2659dcbe240SPoul-Henning Kamp make_dev(&log_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "klog"); 2667198bf47SJulian Elischer } 26753ac6efbSJulian Elischer 26853ac6efbSJulian Elischer SYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,log_drvinit,NULL) 269