1 /* $NetBSD: subr_log.c,v 1.33 2003/09/22 12:59:57 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)subr_log.c 8.3 (Berkeley) 2/14/95 32 */ 33 34 /* 35 * Error log buffer for kernel printf's. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: subr_log.c,v 1.33 2003/09/22 12:59:57 christos Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/proc.h> 44 #include <sys/vnode.h> 45 #include <sys/ioctl.h> 46 #include <sys/msgbuf.h> 47 #include <sys/file.h> 48 #include <sys/signalvar.h> 49 #include <sys/syslog.h> 50 #include <sys/conf.h> 51 #include <sys/select.h> 52 #include <sys/poll.h> 53 54 #define LOG_RDPRI (PZERO + 1) 55 56 #define LOG_ASYNC 0x04 57 #define LOG_RDWAIT 0x08 58 59 struct logsoftc { 60 int sc_state; /* see above for possibilities */ 61 struct selinfo sc_selp; /* process waiting on select call */ 62 pid_t sc_pgid; /* process/group for async I/O */ 63 } logsoftc; 64 65 int log_open; /* also used in log() */ 66 int msgbufmapped; /* is the message buffer mapped */ 67 int msgbufenabled; /* is logging to the buffer enabled */ 68 struct kern_msgbuf *msgbufp; /* the mapped buffer, itself. */ 69 70 dev_type_open(logopen); 71 dev_type_close(logclose); 72 dev_type_read(logread); 73 dev_type_ioctl(logioctl); 74 dev_type_poll(logpoll); 75 dev_type_kqfilter(logkqfilter); 76 77 const struct cdevsw log_cdevsw = { 78 logopen, logclose, logread, nowrite, logioctl, 79 nostop, notty, logpoll, nommap, logkqfilter, 80 }; 81 82 void 83 initmsgbuf(buf, bufsize) 84 caddr_t buf; 85 size_t bufsize; 86 { 87 struct kern_msgbuf *mbp; 88 long new_bufs; 89 90 /* Sanity-check the given size. */ 91 if (bufsize < sizeof(struct kern_msgbuf)) 92 return; 93 94 mbp = msgbufp = (struct kern_msgbuf *)buf; 95 96 new_bufs = bufsize - offsetof(struct kern_msgbuf, msg_bufc); 97 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) || 98 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) || 99 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) { 100 /* 101 * If the buffer magic number is wrong, has changed 102 * size (which shouldn't happen often), or is 103 * internally inconsistent, initialize it. 104 */ 105 106 memset(buf, 0, bufsize); 107 mbp->msg_magic = MSG_MAGIC; 108 mbp->msg_bufs = new_bufs; 109 } 110 111 /* mark it as ready for use. */ 112 msgbufmapped = msgbufenabled = 1; 113 } 114 115 /*ARGSUSED*/ 116 int 117 logopen(dev, flags, mode, p) 118 dev_t dev; 119 int flags, mode; 120 struct proc *p; 121 { 122 struct kern_msgbuf *mbp = msgbufp; 123 124 if (log_open) 125 return (EBUSY); 126 log_open = 1; 127 logsoftc.sc_pgid = p->p_pid; /* signal process only */ 128 /* 129 * The message buffer is initialized during system configuration. 130 * If it's been clobbered, note that and return an error. (This 131 * allows a user to potentially read the buffer via /dev/kmem, 132 * and try to figure out what clobbered it. 133 */ 134 if (mbp->msg_magic != MSG_MAGIC) { 135 msgbufenabled = 0; 136 return (ENXIO); 137 } 138 139 return (0); 140 } 141 142 /*ARGSUSED*/ 143 int 144 logclose(dev, flag, mode, p) 145 dev_t dev; 146 int flag, mode; 147 struct proc *p; 148 { 149 150 log_open = 0; 151 logsoftc.sc_state = 0; 152 return (0); 153 } 154 155 /*ARGSUSED*/ 156 int 157 logread(dev, uio, flag) 158 dev_t dev; 159 struct uio *uio; 160 int flag; 161 { 162 struct kern_msgbuf *mbp = msgbufp; 163 long l; 164 int s; 165 int error = 0; 166 167 s = splhigh(); 168 while (mbp->msg_bufr == mbp->msg_bufx) { 169 if (flag & IO_NDELAY) { 170 splx(s); 171 return (EWOULDBLOCK); 172 } 173 logsoftc.sc_state |= LOG_RDWAIT; 174 error = tsleep((caddr_t)mbp, LOG_RDPRI | PCATCH, 175 "klog", 0); 176 if (error) { 177 splx(s); 178 return (error); 179 } 180 } 181 splx(s); 182 logsoftc.sc_state &= ~LOG_RDWAIT; 183 184 while (uio->uio_resid > 0) { 185 l = mbp->msg_bufx - mbp->msg_bufr; 186 if (l < 0) 187 l = mbp->msg_bufs - mbp->msg_bufr; 188 l = min(l, uio->uio_resid); 189 if (l == 0) 190 break; 191 error = uiomove((caddr_t)&mbp->msg_bufc[mbp->msg_bufr], 192 (int)l, uio); 193 if (error) 194 break; 195 mbp->msg_bufr += l; 196 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 197 mbp->msg_bufr = 0; 198 } 199 return (error); 200 } 201 202 /*ARGSUSED*/ 203 int 204 logpoll(dev, events, p) 205 dev_t dev; 206 int events; 207 struct proc *p; 208 { 209 int revents = 0; 210 int s = splhigh(); 211 212 if (events & (POLLIN | POLLRDNORM)) { 213 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 214 revents |= events & (POLLIN | POLLRDNORM); 215 else 216 selrecord(p, &logsoftc.sc_selp); 217 } 218 219 splx(s); 220 return (revents); 221 } 222 223 static void 224 filt_logrdetach(struct knote *kn) 225 { 226 int s; 227 228 s = splhigh(); 229 SLIST_REMOVE(&logsoftc.sc_selp.sel_klist, kn, knote, kn_selnext); 230 splx(s); 231 } 232 233 static int 234 filt_logread(struct knote *kn, long hint) 235 { 236 237 if (msgbufp->msg_bufr == msgbufp->msg_bufx) 238 return (0); 239 240 if (msgbufp->msg_bufr < msgbufp->msg_bufx) 241 kn->kn_data = msgbufp->msg_bufx - msgbufp->msg_bufr; 242 else 243 kn->kn_data = (msgbufp->msg_bufs - msgbufp->msg_bufr) + 244 msgbufp->msg_bufx; 245 246 return (1); 247 } 248 249 static const struct filterops logread_filtops = 250 { 1, NULL, filt_logrdetach, filt_logread }; 251 252 int 253 logkqfilter(dev_t dev, struct knote *kn) 254 { 255 struct klist *klist; 256 int s; 257 258 switch (kn->kn_filter) { 259 case EVFILT_READ: 260 klist = &logsoftc.sc_selp.sel_klist; 261 kn->kn_fop = &logread_filtops; 262 break; 263 264 default: 265 return (1); 266 } 267 268 kn->kn_hook = NULL; 269 270 s = splhigh(); 271 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 272 splx(s); 273 274 return (0); 275 } 276 277 void 278 logwakeup() 279 { 280 if (!log_open) 281 return; 282 selnotify(&logsoftc.sc_selp, 0); 283 if (logsoftc.sc_state & LOG_ASYNC) 284 fownsignal(logsoftc.sc_pgid, SIGIO, 0, 0, NULL); 285 if (logsoftc.sc_state & LOG_RDWAIT) { 286 wakeup((caddr_t)msgbufp); 287 logsoftc.sc_state &= ~LOG_RDWAIT; 288 } 289 } 290 291 /*ARGSUSED*/ 292 int 293 logioctl(dev, com, data, flag, p) 294 dev_t dev; 295 u_long com; 296 caddr_t data; 297 int flag; 298 struct proc *p; 299 { 300 long l; 301 int s; 302 303 switch (com) { 304 305 /* return number of characters immediately available */ 306 case FIONREAD: 307 s = splhigh(); 308 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 309 splx(s); 310 if (l < 0) 311 l += msgbufp->msg_bufs; 312 *(int *)data = l; 313 break; 314 315 case FIONBIO: 316 break; 317 318 case FIOASYNC: 319 if (*(int *)data) 320 logsoftc.sc_state |= LOG_ASYNC; 321 else 322 logsoftc.sc_state &= ~LOG_ASYNC; 323 break; 324 325 case TIOCSPGRP: 326 case FIOSETOWN: 327 return fsetown(p, &logsoftc.sc_pgid, com, data); 328 329 case TIOCGPGRP: 330 case FIOGETOWN: 331 return fgetown(p, logsoftc.sc_pgid, com, data); 332 333 default: 334 return (EPASSTHROUGH); 335 } 336 return (0); 337 } 338