1 /* 2 * Copyright (c) 1982, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)subr_log.c 8.1 (Berkeley) 6/10/93 30 * $FreeBSD: src/sys/kern/subr_log.c,v 1.39.2.2 2001/06/02 08:11:25 phk Exp $ 31 */ 32 33 /* 34 * Error log buffer for kernel printf's. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/uio.h> 40 #include <sys/conf.h> 41 #include <sys/device.h> 42 #include <sys/proc.h> 43 #include <sys/vnode.h> 44 #include <sys/filio.h> 45 #include <sys/ttycom.h> 46 #include <sys/msgbuf.h> 47 #include <sys/signalvar.h> 48 #include <sys/kernel.h> 49 #include <sys/event.h> 50 #include <sys/filedesc.h> 51 #include <sys/sysctl.h> 52 #include <sys/thread2.h> 53 54 #define LOG_ASYNC 0x04 55 #define LOG_RDWAIT 0x08 56 57 static d_open_t logopen; 58 static d_close_t logclose; 59 static d_read_t logread; 60 static d_ioctl_t logioctl; 61 static d_kqfilter_t logkqfilter; 62 63 static void logtimeout(void *arg); 64 static void logfiltdetach(struct knote *kn); 65 static int logfiltread(struct knote *kn, long hint); 66 67 #define CDEV_MAJOR 7 68 static struct dev_ops log_ops = { 69 { "log", 0, 0 }, 70 .d_open = logopen, 71 .d_close = logclose, 72 .d_read = logread, 73 .d_ioctl = logioctl, 74 .d_kqfilter = logkqfilter 75 }; 76 77 static struct logsoftc { 78 int sc_state; /* see above for possibilities */ 79 struct kqinfo sc_kqp; /* processes waiting on I/O */ 80 struct sigio *sc_sigio; /* information for async I/O */ 81 struct callout sc_callout; /* callout to wakeup syslog */ 82 } logsoftc; 83 84 int log_open; /* also used in log() */ 85 86 /* Times per second to check for a pending syslog wakeup. */ 87 static int log_wakeups_per_second = 5; 88 SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW, 89 &log_wakeups_per_second, 0, ""); 90 91 /*ARGSUSED*/ 92 static int 93 logopen(struct dev_open_args *ap) 94 { 95 struct proc *p = curproc; 96 97 KKASSERT(p != NULL); 98 if (log_open) 99 return (EBUSY); 100 log_open = 1; 101 callout_init_mp(&logsoftc.sc_callout); 102 fsetown(p->p_pid, &logsoftc.sc_sigio); /* signal process only */ 103 callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 104 logtimeout, NULL); 105 return (0); 106 } 107 108 /*ARGSUSED*/ 109 static int 110 logclose(struct dev_close_args *ap) 111 { 112 log_open = 0; 113 callout_cancel(&logsoftc.sc_callout); 114 logsoftc.sc_state = 0; 115 funsetown(&logsoftc.sc_sigio); 116 return (0); 117 } 118 119 /*ARGSUSED*/ 120 static int 121 logread(struct dev_read_args *ap) 122 { 123 struct uio *uio = ap->a_uio; 124 struct msgbuf *mbp = msgbufp; 125 int error = 0; 126 u_int lindex; 127 u_int xindex; 128 u_int lindex_modulo; 129 u_int n; 130 131 /* 132 * Handle blocking 133 */ 134 while (mbp->msg_bufl == mbp->msg_bufx) { 135 crit_enter(); 136 if (ap->a_ioflag & IO_NDELAY) { 137 crit_exit(); 138 return (EWOULDBLOCK); 139 } 140 atomic_set_int(&logsoftc.sc_state, LOG_RDWAIT); 141 if ((error = tsleep((caddr_t)mbp, PCATCH, "klog", 0))) { 142 crit_exit(); 143 return (error); 144 } 145 /* don't bother clearing LOG_RDWAIT */ 146 crit_exit(); 147 } 148 149 /* 150 * Loop reading data 151 */ 152 while (uio->uio_resid > 0 && mbp->msg_bufl != mbp->msg_bufx) { 153 lindex = mbp->msg_bufl; 154 xindex = mbp->msg_bufx; 155 cpu_ccfence(); 156 157 /* 158 * Clean up if too much time has passed causing us to wrap 159 * the buffer. This will lose some data. If more than ~4GB 160 * then this will lose even more data. 161 */ 162 n = xindex - lindex; 163 if (n > mbp->msg_size - 1024) { 164 lindex = xindex - mbp->msg_size + 2048; 165 n = xindex - lindex; 166 } 167 168 /* 169 * Calculates contiguous bytes we can read in one loop. 170 */ 171 lindex_modulo = lindex % mbp->msg_size; 172 n = mbp->msg_size - lindex_modulo; 173 if (n > xindex - lindex) 174 n = xindex - lindex; 175 if ((size_t)n > uio->uio_resid) 176 n = (u_int)uio->uio_resid; 177 178 /* 179 * Copy (n) bytes of data. 180 */ 181 error = uiomove((caddr_t)msgbufp->msg_ptr + lindex_modulo, 182 (size_t)n, uio); 183 if (error) 184 break; 185 mbp->msg_bufl = lindex + n; 186 } 187 return (error); 188 } 189 190 static struct filterops logread_filtops = 191 { FILTEROP_ISFD, NULL, logfiltdetach, logfiltread }; 192 193 static int 194 logkqfilter(struct dev_kqfilter_args *ap) 195 { 196 struct knote *kn = ap->a_kn; 197 struct klist *klist = &logsoftc.sc_kqp.ki_note; 198 199 ap->a_result = 0; 200 switch (kn->kn_filter) { 201 case EVFILT_READ: 202 kn->kn_fop = &logread_filtops; 203 break; 204 default: 205 ap->a_result = EOPNOTSUPP; 206 return (0); 207 } 208 209 knote_insert(klist, kn); 210 211 return (0); 212 } 213 214 static void 215 logfiltdetach(struct knote *kn) 216 { 217 struct klist *klist = &logsoftc.sc_kqp.ki_note; 218 219 knote_remove(klist, kn); 220 } 221 222 static int 223 logfiltread(struct knote *kn, long hint) 224 { 225 int ret = 0; 226 227 crit_enter(); 228 if (msgbufp->msg_bufl != msgbufp->msg_bufx) 229 ret = 1; 230 crit_exit(); 231 232 return (ret); 233 } 234 235 static void 236 logtimeout(void *arg) 237 { 238 if (!log_open) 239 return; 240 if (msgbuftrigger == 0) { 241 callout_reset(&logsoftc.sc_callout, 242 hz / log_wakeups_per_second, logtimeout, NULL); 243 return; 244 } 245 msgbuftrigger = 0; 246 KNOTE(&logsoftc.sc_kqp.ki_note, 0); 247 if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL) 248 pgsigio(logsoftc.sc_sigio, SIGIO, 0); 249 if (logsoftc.sc_state & LOG_RDWAIT) { 250 atomic_clear_int(&logsoftc.sc_state, LOG_RDWAIT); 251 wakeup((caddr_t)msgbufp); 252 } 253 callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 254 logtimeout, NULL); 255 } 256 257 /*ARGSUSED*/ 258 static int 259 logioctl(struct dev_ioctl_args *ap) 260 { 261 struct msgbuf *mbp = msgbufp; 262 u_int lindex; 263 u_int xindex; 264 u_int n; 265 266 switch (ap->a_cmd) { 267 case FIONREAD: 268 lindex = mbp->msg_bufl; 269 xindex = mbp->msg_bufx; 270 cpu_ccfence(); 271 272 /* 273 * Clean up if too much time has passed causing us to wrap 274 * the buffer. This will lose some data. If more than ~4GB 275 * then this will lose even more data. 276 */ 277 n = xindex - lindex; 278 if (n > mbp->msg_size - 1024) { 279 lindex = xindex - mbp->msg_size + 2048; 280 n = xindex - lindex; 281 } 282 *(int *)ap->a_data = n; 283 break; 284 285 case FIOASYNC: 286 if (*(int *)ap->a_data) 287 atomic_set_int(&logsoftc.sc_state, LOG_ASYNC); 288 else 289 atomic_clear_int(&logsoftc.sc_state, LOG_ASYNC); 290 break; 291 292 case FIOSETOWN: 293 return (fsetown(*(int *)ap->a_data, &logsoftc.sc_sigio)); 294 295 case FIOGETOWN: 296 *(int *)ap->a_data = fgetown(&logsoftc.sc_sigio); 297 break; 298 299 /* This is deprecated, FIOSETOWN should be used instead. */ 300 case TIOCSPGRP: 301 return (fsetown(-(*(int *)ap->a_data), &logsoftc.sc_sigio)); 302 303 /* This is deprecated, FIOGETOWN should be used instead */ 304 case TIOCGPGRP: 305 *(int *)ap->a_data = -fgetown(&logsoftc.sc_sigio); 306 break; 307 308 default: 309 return (ENOTTY); 310 } 311 return (0); 312 } 313 314 static void 315 log_drvinit(void *unused) 316 { 317 make_dev(&log_ops, 0, UID_ROOT, GID_WHEEL, 0600, "klog"); 318 } 319 320 SYSINIT(logdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, log_drvinit, 321 NULL); 322