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/conf.h> 40 #include <sys/device.h> 41 #include <sys/proc.h> 42 #include <sys/vnode.h> 43 #include <sys/filio.h> 44 #include <sys/ttycom.h> 45 #include <sys/msgbuf.h> 46 #include <sys/signalvar.h> 47 #include <sys/kernel.h> 48 #include <sys/event.h> 49 #include <sys/filedesc.h> 50 #include <sys/sysctl.h> 51 #include <sys/thread2.h> 52 53 #define LOG_ASYNC 0x04 54 #define LOG_RDWAIT 0x08 55 56 static d_open_t logopen; 57 static d_close_t logclose; 58 static d_read_t logread; 59 static d_ioctl_t logioctl; 60 static d_kqfilter_t logkqfilter; 61 62 static void logtimeout(void *arg); 63 static void logfiltdetach(struct knote *kn); 64 static int logfiltread(struct knote *kn, long hint); 65 66 #define CDEV_MAJOR 7 67 static struct dev_ops log_ops = { 68 { "log", 0, 0 }, 69 .d_open = logopen, 70 .d_close = logclose, 71 .d_read = logread, 72 .d_ioctl = logioctl, 73 .d_kqfilter = logkqfilter 74 }; 75 76 static struct logsoftc { 77 int sc_state; /* see above for possibilities */ 78 struct kqinfo sc_kqp; /* processes waiting on I/O */ 79 struct sigio *sc_sigio; /* information for async I/O */ 80 struct callout sc_callout; /* callout to wakeup syslog */ 81 } logsoftc; 82 83 int log_open; /* also used in log() */ 84 85 /* Times per second to check for a pending syslog wakeup. */ 86 static int log_wakeups_per_second = 5; 87 SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW, 88 &log_wakeups_per_second, 0, ""); 89 90 /*ARGSUSED*/ 91 static int 92 logopen(struct dev_open_args *ap) 93 { 94 struct proc *p = curproc; 95 96 KKASSERT(p != NULL); 97 if (log_open) 98 return (EBUSY); 99 log_open = 1; 100 callout_init_mp(&logsoftc.sc_callout); 101 fsetown(p->p_pid, &logsoftc.sc_sigio); /* signal process only */ 102 callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 103 logtimeout, NULL); 104 return (0); 105 } 106 107 /*ARGSUSED*/ 108 static int 109 logclose(struct dev_close_args *ap) 110 { 111 log_open = 0; 112 callout_cancel(&logsoftc.sc_callout); 113 logsoftc.sc_state = 0; 114 funsetown(&logsoftc.sc_sigio); 115 return (0); 116 } 117 118 /*ARGSUSED*/ 119 static int 120 logread(struct dev_read_args *ap) 121 { 122 struct uio *uio = ap->a_uio; 123 struct msgbuf *mbp = msgbufp; 124 int error = 0; 125 u_int lindex; 126 u_int xindex; 127 u_int lindex_modulo; 128 u_int n; 129 130 /* 131 * Handle blocking 132 */ 133 while (mbp->msg_bufl == mbp->msg_bufx) { 134 crit_enter(); 135 if (ap->a_ioflag & IO_NDELAY) { 136 crit_exit(); 137 return (EWOULDBLOCK); 138 } 139 atomic_set_int(&logsoftc.sc_state, LOG_RDWAIT); 140 if ((error = tsleep((caddr_t)mbp, PCATCH, "klog", 0))) { 141 crit_exit(); 142 return (error); 143 } 144 /* don't bother clearing LOG_RDWAIT */ 145 crit_exit(); 146 } 147 148 /* 149 * Loop reading data 150 */ 151 while (uio->uio_resid > 0 && mbp->msg_bufl != mbp->msg_bufx) { 152 lindex = mbp->msg_bufl; 153 xindex = mbp->msg_bufx; 154 cpu_ccfence(); 155 156 /* 157 * Clean up if too much time has passed causing us to wrap 158 * the buffer. This will lose some data. If more than ~4GB 159 * then this will lose even more data. 160 */ 161 n = xindex - lindex; 162 if (n > mbp->msg_size - 1024) { 163 lindex = xindex - mbp->msg_size + 2048; 164 n = xindex - lindex; 165 } 166 167 /* 168 * Calculates contiguous bytes we can read in one loop. 169 */ 170 lindex_modulo = lindex % mbp->msg_size; 171 n = mbp->msg_size - lindex_modulo; 172 if (n > xindex - lindex) 173 n = xindex - lindex; 174 if ((size_t)n > uio->uio_resid) 175 n = (u_int)uio->uio_resid; 176 177 /* 178 * Copy (n) bytes of data. 179 */ 180 error = uiomove((caddr_t)msgbufp->msg_ptr + lindex_modulo, 181 (size_t)n, uio); 182 if (error) 183 break; 184 mbp->msg_bufl = lindex + n; 185 } 186 return (error); 187 } 188 189 static struct filterops logread_filtops = 190 { FILTEROP_ISFD, NULL, logfiltdetach, logfiltread }; 191 192 static int 193 logkqfilter(struct dev_kqfilter_args *ap) 194 { 195 struct knote *kn = ap->a_kn; 196 struct klist *klist = &logsoftc.sc_kqp.ki_note; 197 198 ap->a_result = 0; 199 switch (kn->kn_filter) { 200 case EVFILT_READ: 201 kn->kn_fop = &logread_filtops; 202 break; 203 default: 204 ap->a_result = EOPNOTSUPP; 205 return (0); 206 } 207 208 knote_insert(klist, kn); 209 210 return (0); 211 } 212 213 static void 214 logfiltdetach(struct knote *kn) 215 { 216 struct klist *klist = &logsoftc.sc_kqp.ki_note; 217 218 knote_remove(klist, kn); 219 } 220 221 static int 222 logfiltread(struct knote *kn, long hint) 223 { 224 int ret = 0; 225 226 crit_enter(); 227 if (msgbufp->msg_bufl != msgbufp->msg_bufx) 228 ret = 1; 229 crit_exit(); 230 231 return (ret); 232 } 233 234 static void 235 logtimeout(void *arg) 236 { 237 if (!log_open) 238 return; 239 if (msgbuftrigger == 0) { 240 callout_reset(&logsoftc.sc_callout, 241 hz / log_wakeups_per_second, logtimeout, NULL); 242 return; 243 } 244 msgbuftrigger = 0; 245 KNOTE(&logsoftc.sc_kqp.ki_note, 0); 246 if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL) 247 pgsigio(logsoftc.sc_sigio, SIGIO, 0); 248 if (logsoftc.sc_state & LOG_RDWAIT) { 249 atomic_clear_int(&logsoftc.sc_state, LOG_RDWAIT); 250 wakeup((caddr_t)msgbufp); 251 } 252 callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, 253 logtimeout, NULL); 254 } 255 256 /*ARGSUSED*/ 257 static int 258 logioctl(struct dev_ioctl_args *ap) 259 { 260 struct msgbuf *mbp = msgbufp; 261 u_int lindex; 262 u_int xindex; 263 u_int n; 264 265 switch (ap->a_cmd) { 266 case FIONREAD: 267 lindex = mbp->msg_bufl; 268 xindex = mbp->msg_bufx; 269 cpu_ccfence(); 270 271 /* 272 * Clean up if too much time has passed causing us to wrap 273 * the buffer. This will lose some data. If more than ~4GB 274 * then this will lose even more data. 275 */ 276 n = xindex - lindex; 277 if (n > mbp->msg_size - 1024) { 278 lindex = xindex - mbp->msg_size + 2048; 279 n = xindex - lindex; 280 } 281 *(int *)ap->a_data = n; 282 break; 283 284 case FIOASYNC: 285 if (*(int *)ap->a_data) 286 atomic_set_int(&logsoftc.sc_state, LOG_ASYNC); 287 else 288 atomic_clear_int(&logsoftc.sc_state, LOG_ASYNC); 289 break; 290 291 case FIOSETOWN: 292 return (fsetown(*(int *)ap->a_data, &logsoftc.sc_sigio)); 293 294 case FIOGETOWN: 295 *(int *)ap->a_data = fgetown(&logsoftc.sc_sigio); 296 break; 297 298 /* This is deprecated, FIOSETOWN should be used instead. */ 299 case TIOCSPGRP: 300 return (fsetown(-(*(int *)ap->a_data), &logsoftc.sc_sigio)); 301 302 /* This is deprecated, FIOGETOWN should be used instead */ 303 case TIOCGPGRP: 304 *(int *)ap->a_data = -fgetown(&logsoftc.sc_sigio); 305 break; 306 307 default: 308 return (ENOTTY); 309 } 310 return (0); 311 } 312 313 static void 314 log_drvinit(void *unused) 315 { 316 make_dev(&log_ops, 0, UID_ROOT, GID_WHEEL, 0600, "klog"); 317 } 318 319 SYSINIT(logdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, log_drvinit, 320 NULL); 321