19454b2d8SWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29df8bae1dSRodney W. Grimes * @(#)subr_log.c 8.1 (Berkeley) 6/10/93 30df8bae1dSRodney W. Grimes */ 31df8bae1dSRodney W. Grimes 32df8bae1dSRodney W. Grimes /* 33df8bae1dSRodney W. Grimes * Error log buffer for kernel printf's. 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36677b542eSDavid E. O'Brien #include <sys/cdefs.h> 37677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 38677b542eSDavid E. O'Brien 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 4198d93822SBruce Evans #include <sys/conf.h> 42df8bae1dSRodney W. Grimes #include <sys/proc.h> 43df8bae1dSRodney W. Grimes #include <sys/vnode.h> 4420982410SBruce Evans #include <sys/filio.h> 4520982410SBruce Evans #include <sys/ttycom.h> 46df8bae1dSRodney W. Grimes #include <sys/msgbuf.h> 47797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 4853ac6efbSJulian Elischer #include <sys/kernel.h> 491514b90fSPeter Wemm #include <sys/poll.h> 50831d27a9SDon Lewis #include <sys/filedesc.h> 51a9b13707SJohn Baldwin #include <sys/sysctl.h> 5253ac6efbSJulian Elischer 53df8bae1dSRodney W. Grimes #define LOG_RDPRI (PZERO + 1) 54df8bae1dSRodney W. Grimes 55df8bae1dSRodney W. Grimes #define LOG_ASYNC 0x04 56df8bae1dSRodney W. Grimes 5787f6c662SJulian Elischer static d_open_t logopen; 5887f6c662SJulian Elischer static d_close_t logclose; 5987f6c662SJulian Elischer static d_read_t logread; 6087f6c662SJulian Elischer static d_ioctl_t logioctl; 611514b90fSPeter Wemm static d_poll_t logpoll; 626af519cfSKonstantin Belousov static d_kqfilter_t logkqfilter; 6387f6c662SJulian Elischer 64a9b13707SJohn Baldwin static void logtimeout(void *arg); 65a9b13707SJohn Baldwin 664e2f199eSPoul-Henning Kamp static struct cdevsw log_cdevsw = { 67dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 687ac40f5fSPoul-Henning Kamp .d_open = logopen, 697ac40f5fSPoul-Henning Kamp .d_close = logclose, 707ac40f5fSPoul-Henning Kamp .d_read = logread, 717ac40f5fSPoul-Henning Kamp .d_ioctl = logioctl, 727ac40f5fSPoul-Henning Kamp .d_poll = logpoll, 736af519cfSKonstantin Belousov .d_kqfilter = logkqfilter, 747ac40f5fSPoul-Henning Kamp .d_name = "log", 754e2f199eSPoul-Henning Kamp }; 7687f6c662SJulian Elischer 776af519cfSKonstantin Belousov static int logkqread(struct knote *note, long hint); 786af519cfSKonstantin Belousov static void logkqdetach(struct knote *note); 796af519cfSKonstantin Belousov 806af519cfSKonstantin Belousov static struct filterops log_read_filterops = { 816af519cfSKonstantin Belousov .f_isfd = 1, 826af519cfSKonstantin Belousov .f_attach = NULL, 836af519cfSKonstantin Belousov .f_detach = logkqdetach, 846af519cfSKonstantin Belousov .f_event = logkqread, 856af519cfSKonstantin Belousov }; 866af519cfSKonstantin Belousov 8787b6de2bSPoul-Henning Kamp static struct logsoftc { 88df8bae1dSRodney W. Grimes int sc_state; /* see above for possibilities */ 89df8bae1dSRodney W. Grimes struct selinfo sc_selp; /* process waiting on select call */ 9062d6ce3aSDon Lewis struct sigio *sc_sigio; /* information for async I/O */ 91a9b13707SJohn Baldwin struct callout sc_callout; /* callout to wakeup syslog */ 92df8bae1dSRodney W. Grimes } logsoftc; 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes int log_open; /* also used in log() */ 95ca1d2f65SEd Schouten static struct cv log_wakeup; 96ca1d2f65SEd Schouten struct mtx msgbuf_lock; 97ca1d2f65SEd Schouten MTX_SYSINIT(msgbuf_lock, &msgbuf_lock, "msgbuf lock", MTX_DEF); 98df8bae1dSRodney W. Grimes 99a9b13707SJohn Baldwin /* Times per second to check for a pending syslog wakeup. */ 100a9b13707SJohn Baldwin static int log_wakeups_per_second = 5; 101a9b13707SJohn Baldwin SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW, 102a9b13707SJohn Baldwin &log_wakeups_per_second, 0, ""); 103a9b13707SJohn Baldwin 104df8bae1dSRodney W. Grimes /*ARGSUSED*/ 10587f6c662SJulian Elischer static int 10689c9c53dSPoul-Henning Kamp logopen(struct cdev *dev, int flags, int mode, struct thread *td) 107df8bae1dSRodney W. Grimes { 108ca1d2f65SEd Schouten 109b2b417bbSBosko Milekic if (log_wakeups_per_second < 1) { 110b2b417bbSBosko Milekic printf("syslog wakeup is less than one. Adjusting to 1.\n"); 111b2b417bbSBosko Milekic log_wakeups_per_second = 1; 112b2b417bbSBosko Milekic } 113ca1d2f65SEd Schouten 114ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 115ca1d2f65SEd Schouten if (log_open) { 116ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 117ca1d2f65SEd Schouten return (EBUSY); 118ca1d2f65SEd Schouten } 119ca1d2f65SEd Schouten log_open = 1; 120*c38250c9SDavide Italiano callout_reset_sbt(&logsoftc.sc_callout, 121*c38250c9SDavide Italiano SBT_1S / log_wakeups_per_second, 0, logtimeout, NULL, C_PREL(1)); 122ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 123ca1d2f65SEd Schouten 124ca1d2f65SEd Schouten fsetown(td->td_proc->p_pid, &logsoftc.sc_sigio); /* signal process only */ 125df8bae1dSRodney W. Grimes return (0); 126df8bae1dSRodney W. Grimes } 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes /*ARGSUSED*/ 12987f6c662SJulian Elischer static int 13089c9c53dSPoul-Henning Kamp logclose(struct cdev *dev, int flag, int mode, struct thread *td) 131df8bae1dSRodney W. Grimes { 132df8bae1dSRodney W. Grimes 133ca1d2f65SEd Schouten funsetown(&logsoftc.sc_sigio); 134ca1d2f65SEd Schouten 135ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 1364787f91dSPoul-Henning Kamp callout_stop(&logsoftc.sc_callout); 137df8bae1dSRodney W. Grimes logsoftc.sc_state = 0; 138ca1d2f65SEd Schouten log_open = 0; 139ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 140ca1d2f65SEd Schouten 141df8bae1dSRodney W. Grimes return (0); 142df8bae1dSRodney W. Grimes } 143df8bae1dSRodney W. Grimes 144df8bae1dSRodney W. Grimes /*ARGSUSED*/ 14587f6c662SJulian Elischer static int 14689c9c53dSPoul-Henning Kamp logread(struct cdev *dev, struct uio *uio, int flag) 147df8bae1dSRodney W. Grimes { 1484784a469SIan Dowse char buf[128]; 14906b6617eSPoul-Henning Kamp struct msgbuf *mbp = msgbufp; 150ca1d2f65SEd Schouten int error = 0, l; 151df8bae1dSRodney W. Grimes 152ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 1534784a469SIan Dowse while (msgbuf_getcount(mbp) == 0) { 154df8bae1dSRodney W. Grimes if (flag & IO_NDELAY) { 155ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 156df8bae1dSRodney W. Grimes return (EWOULDBLOCK); 157df8bae1dSRodney W. Grimes } 158ca1d2f65SEd Schouten if ((error = cv_wait_sig(&log_wakeup, &msgbuf_lock)) != 0) { 159ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 160df8bae1dSRodney W. Grimes return (error); 161df8bae1dSRodney W. Grimes } 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes while (uio->uio_resid > 0) { 1654784a469SIan Dowse l = imin(sizeof(buf), uio->uio_resid); 1664784a469SIan Dowse l = msgbuf_getbytes(mbp, buf, l); 167df8bae1dSRodney W. Grimes if (l == 0) 168df8bae1dSRodney W. Grimes break; 169ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 1704784a469SIan Dowse error = uiomove(buf, l, uio); 171ca1d2f65SEd Schouten if (error || uio->uio_resid == 0) 172ca1d2f65SEd Schouten return (error); 173ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 174df8bae1dSRodney W. Grimes } 175ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 176df8bae1dSRodney W. Grimes return (error); 177df8bae1dSRodney W. Grimes } 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes /*ARGSUSED*/ 18087f6c662SJulian Elischer static int 18189c9c53dSPoul-Henning Kamp logpoll(struct cdev *dev, int events, struct thread *td) 182df8bae1dSRodney W. Grimes { 1831514b90fSPeter Wemm int revents = 0; 184df8bae1dSRodney W. Grimes 185dfd5dee1SPeter Wemm if (events & (POLLIN | POLLRDNORM)) { 186ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 1874784a469SIan Dowse if (msgbuf_getcount(msgbufp) > 0) 1881514b90fSPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 1891514b90fSPeter Wemm else 190ed01445dSJohn Baldwin selrecord(td, &logsoftc.sc_selp); 191ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 192dfd5dee1SPeter Wemm } 1931514b90fSPeter Wemm return (revents); 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes 1966af519cfSKonstantin Belousov static int 1976af519cfSKonstantin Belousov logkqfilter(struct cdev *dev, struct knote *kn) 1986af519cfSKonstantin Belousov { 1996af519cfSKonstantin Belousov 2006af519cfSKonstantin Belousov if (kn->kn_filter != EVFILT_READ) 2016af519cfSKonstantin Belousov return (EINVAL); 2026af519cfSKonstantin Belousov 2036af519cfSKonstantin Belousov kn->kn_fop = &log_read_filterops; 2046af519cfSKonstantin Belousov kn->kn_hook = NULL; 2056af519cfSKonstantin Belousov 2066af519cfSKonstantin Belousov mtx_lock(&msgbuf_lock); 2076af519cfSKonstantin Belousov knlist_add(&logsoftc.sc_selp.si_note, kn, 1); 2086af519cfSKonstantin Belousov mtx_unlock(&msgbuf_lock); 2096af519cfSKonstantin Belousov return (0); 2106af519cfSKonstantin Belousov } 2116af519cfSKonstantin Belousov 2126af519cfSKonstantin Belousov static int 2136af519cfSKonstantin Belousov logkqread(struct knote *kn, long hint) 2146af519cfSKonstantin Belousov { 2156af519cfSKonstantin Belousov 2166af519cfSKonstantin Belousov mtx_assert(&msgbuf_lock, MA_OWNED); 2176af519cfSKonstantin Belousov kn->kn_data = msgbuf_getcount(msgbufp); 2186af519cfSKonstantin Belousov return (kn->kn_data != 0); 2196af519cfSKonstantin Belousov } 2206af519cfSKonstantin Belousov 2216af519cfSKonstantin Belousov static void 2226af519cfSKonstantin Belousov logkqdetach(struct knote *kn) 2236af519cfSKonstantin Belousov { 2246af519cfSKonstantin Belousov 2256af519cfSKonstantin Belousov mtx_lock(&msgbuf_lock); 2266af519cfSKonstantin Belousov knlist_remove(&logsoftc.sc_selp.si_note, kn, 1); 2276af519cfSKonstantin Belousov mtx_unlock(&msgbuf_lock); 2286af519cfSKonstantin Belousov } 2296af519cfSKonstantin Belousov 230a9b13707SJohn Baldwin static void 231a9b13707SJohn Baldwin logtimeout(void *arg) 232a9b13707SJohn Baldwin { 233a9b13707SJohn Baldwin 234df8bae1dSRodney W. Grimes if (!log_open) 235df8bae1dSRodney W. Grimes return; 236*c38250c9SDavide Italiano if (msgbuftrigger == 0) 237*c38250c9SDavide Italiano goto done; 2384787f91dSPoul-Henning Kamp msgbuftrigger = 0; 239512824f8SSeigo Tanimura selwakeuppri(&logsoftc.sc_selp, LOG_RDPRI); 2406af519cfSKonstantin Belousov KNOTE_LOCKED(&logsoftc.sc_selp.si_note, 0); 241831d27a9SDon Lewis if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL) 242f1320723SAlfred Perlstein pgsigio(&logsoftc.sc_sigio, SIGIO, 0); 243ca1d2f65SEd Schouten cv_broadcastpri(&log_wakeup, LOG_RDPRI); 244*c38250c9SDavide Italiano done: 245*c38250c9SDavide Italiano if (log_wakeups_per_second < 1) { 246*c38250c9SDavide Italiano printf("syslog wakeup is less than one. Adjusting to 1.\n"); 247*c38250c9SDavide Italiano log_wakeups_per_second = 1; 248*c38250c9SDavide Italiano } 249*c38250c9SDavide Italiano callout_reset_sbt(&logsoftc.sc_callout, 250*c38250c9SDavide Italiano SBT_1S / log_wakeups_per_second, 0, logtimeout, NULL, C_PREL(1)); 251df8bae1dSRodney W. Grimes } 252df8bae1dSRodney W. Grimes 253df8bae1dSRodney W. Grimes /*ARGSUSED*/ 25487f6c662SJulian Elischer static int 25589c9c53dSPoul-Henning Kamp logioctl(struct cdev *dev, u_long com, caddr_t data, int flag, struct thread *td) 256df8bae1dSRodney W. Grimes { 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes switch (com) { 259df8bae1dSRodney W. Grimes 260df8bae1dSRodney W. Grimes /* return number of characters immediately available */ 261df8bae1dSRodney W. Grimes case FIONREAD: 2624784a469SIan Dowse *(int *)data = msgbuf_getcount(msgbufp); 263df8bae1dSRodney W. Grimes break; 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes case FIONBIO: 266df8bae1dSRodney W. Grimes break; 267df8bae1dSRodney W. Grimes 268df8bae1dSRodney W. Grimes case FIOASYNC: 269ca1d2f65SEd Schouten mtx_lock(&msgbuf_lock); 270df8bae1dSRodney W. Grimes if (*(int *)data) 271df8bae1dSRodney W. Grimes logsoftc.sc_state |= LOG_ASYNC; 272df8bae1dSRodney W. Grimes else 273df8bae1dSRodney W. Grimes logsoftc.sc_state &= ~LOG_ASYNC; 274ca1d2f65SEd Schouten mtx_unlock(&msgbuf_lock); 275df8bae1dSRodney W. Grimes break; 276df8bae1dSRodney W. Grimes 277831d27a9SDon Lewis case FIOSETOWN: 278831d27a9SDon Lewis return (fsetown(*(int *)data, &logsoftc.sc_sigio)); 279831d27a9SDon Lewis 280831d27a9SDon Lewis case FIOGETOWN: 28191e97a82SDon Lewis *(int *)data = fgetown(&logsoftc.sc_sigio); 282df8bae1dSRodney W. Grimes break; 283df8bae1dSRodney W. Grimes 284831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 285831d27a9SDon Lewis case TIOCSPGRP: 286831d27a9SDon Lewis return (fsetown(-(*(int *)data), &logsoftc.sc_sigio)); 287831d27a9SDon Lewis 288831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead */ 289df8bae1dSRodney W. Grimes case TIOCGPGRP: 29091e97a82SDon Lewis *(int *)data = -fgetown(&logsoftc.sc_sigio); 291df8bae1dSRodney W. Grimes break; 292df8bae1dSRodney W. Grimes 293df8bae1dSRodney W. Grimes default: 294bcac5617SJordan K. Hubbard return (ENOTTY); 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes return (0); 297df8bae1dSRodney W. Grimes } 29853ac6efbSJulian Elischer 29987f6c662SJulian Elischer static void 30006b6617eSPoul-Henning Kamp log_drvinit(void *unused) 30153ac6efbSJulian Elischer { 30206b6617eSPoul-Henning Kamp 303ca1d2f65SEd Schouten cv_init(&log_wakeup, "klog"); 304ca1d2f65SEd Schouten callout_init_mtx(&logsoftc.sc_callout, &msgbuf_lock, 0); 3056af519cfSKonstantin Belousov knlist_init_mtx(&logsoftc.sc_selp.si_note, &msgbuf_lock); 30623b70c1aSKonstantin Belousov make_dev_credf(MAKEDEV_ETERNAL, &log_cdevsw, 0, NULL, UID_ROOT, 30723b70c1aSKonstantin Belousov GID_WHEEL, 0600, "klog"); 3087198bf47SJulian Elischer } 30953ac6efbSJulian Elischer 310237fdd78SRobert Watson SYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,log_drvinit,NULL); 311