1 /* $NetBSD: subr_log.c,v 1.50 2008/04/28 20:24:04 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)subr_log.c 8.3 (Berkeley) 2/14/95 61 */ 62 63 /* 64 * Error log buffer for kernel printf's. 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: subr_log.c,v 1.50 2008/04/28 20:24:04 martin Exp $"); 69 70 #include <sys/param.h> 71 #include <sys/systm.h> 72 #include <sys/kernel.h> 73 #include <sys/proc.h> 74 #include <sys/vnode.h> 75 #include <sys/ioctl.h> 76 #include <sys/msgbuf.h> 77 #include <sys/file.h> 78 #include <sys/syslog.h> 79 #include <sys/conf.h> 80 #include <sys/select.h> 81 #include <sys/poll.h> 82 #include <sys/intr.h> 83 84 static void logsoftintr(void *); 85 86 static bool log_async; 87 static struct selinfo log_selp; /* process waiting on select call */ 88 static pid_t log_pgid; /* process/group for async I/O */ 89 static kcondvar_t log_cv; 90 static void *log_sih; 91 92 kmutex_t log_lock; 93 int log_open; /* also used in log() */ 94 int msgbufmapped; /* is the message buffer mapped */ 95 int msgbufenabled; /* is logging to the buffer enabled */ 96 struct kern_msgbuf *msgbufp; /* the mapped buffer, itself. */ 97 98 void 99 initmsgbuf(void *bf, size_t bufsize) 100 { 101 struct kern_msgbuf *mbp; 102 long new_bufs; 103 104 /* Sanity-check the given size. */ 105 if (bufsize < sizeof(struct kern_msgbuf)) 106 return; 107 108 mbp = msgbufp = (struct kern_msgbuf *)bf; 109 110 new_bufs = bufsize - offsetof(struct kern_msgbuf, msg_bufc); 111 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) || 112 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) || 113 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) { 114 /* 115 * If the buffer magic number is wrong, has changed 116 * size (which shouldn't happen often), or is 117 * internally inconsistent, initialize it. 118 */ 119 120 memset(bf, 0, bufsize); 121 mbp->msg_magic = MSG_MAGIC; 122 mbp->msg_bufs = new_bufs; 123 } 124 125 /* mark it as ready for use. */ 126 msgbufmapped = msgbufenabled = 1; 127 } 128 129 void 130 loginit(void) 131 { 132 133 mutex_init(&log_lock, MUTEX_DEFAULT, IPL_VM); 134 selinit(&log_selp); 135 cv_init(&log_cv, "klog"); 136 log_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, 137 logsoftintr, NULL); 138 } 139 140 /*ARGSUSED*/ 141 static int 142 logopen(dev_t dev, int flags, int mode, struct lwp *l) 143 { 144 struct kern_msgbuf *mbp = msgbufp; 145 int error = 0; 146 147 mutex_spin_enter(&log_lock); 148 if (log_open) { 149 error = EBUSY; 150 } else { 151 log_open = 1; 152 log_pgid = l->l_proc->p_pid; /* signal process only */ 153 /* 154 * The message buffer is initialized during system 155 * configuration. If it's been clobbered, note that 156 * and return an error. (This allows a user to read 157 * the buffer via /dev/kmem, and try to figure out 158 * what clobbered it. 159 */ 160 if (mbp->msg_magic != MSG_MAGIC) { 161 msgbufenabled = 0; 162 error = ENXIO; 163 } 164 } 165 mutex_spin_exit(&log_lock); 166 167 return error; 168 } 169 170 /*ARGSUSED*/ 171 static int 172 logclose(dev_t dev, int flag, int mode, struct lwp *l) 173 { 174 175 mutex_spin_enter(&log_lock); 176 log_pgid = 0; 177 log_open = 0; 178 log_async = 0; 179 mutex_spin_exit(&log_lock); 180 181 return 0; 182 } 183 184 /*ARGSUSED*/ 185 static int 186 logread(dev_t dev, struct uio *uio, int flag) 187 { 188 struct kern_msgbuf *mbp = msgbufp; 189 long l; 190 int error = 0; 191 192 mutex_spin_enter(&log_lock); 193 while (mbp->msg_bufr == mbp->msg_bufx) { 194 if (flag & IO_NDELAY) { 195 mutex_spin_exit(&log_lock); 196 return EWOULDBLOCK; 197 } 198 error = cv_wait_sig(&log_cv, &log_lock); 199 if (error) { 200 mutex_spin_exit(&log_lock); 201 return error; 202 } 203 } 204 while (uio->uio_resid > 0) { 205 l = mbp->msg_bufx - mbp->msg_bufr; 206 if (l < 0) 207 l = mbp->msg_bufs - mbp->msg_bufr; 208 l = min(l, uio->uio_resid); 209 if (l == 0) 210 break; 211 mutex_spin_exit(&log_lock); 212 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], (int)l, uio); 213 mutex_spin_enter(&log_lock); 214 if (error) 215 break; 216 mbp->msg_bufr += l; 217 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 218 mbp->msg_bufr = 0; 219 } 220 mutex_spin_exit(&log_lock); 221 222 return error; 223 } 224 225 /*ARGSUSED*/ 226 static int 227 logpoll(dev_t dev, int events, struct lwp *l) 228 { 229 int revents = 0; 230 231 if (events & (POLLIN | POLLRDNORM)) { 232 mutex_spin_enter(&log_lock); 233 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 234 revents |= events & (POLLIN | POLLRDNORM); 235 else 236 selrecord(l, &log_selp); 237 mutex_spin_exit(&log_lock); 238 } 239 240 return revents; 241 } 242 243 static void 244 filt_logrdetach(struct knote *kn) 245 { 246 247 mutex_spin_enter(&log_lock); 248 SLIST_REMOVE(&log_selp.sel_klist, kn, knote, kn_selnext); 249 mutex_spin_exit(&log_lock); 250 } 251 252 static int 253 filt_logread(struct knote *kn, long hint) 254 { 255 int rv; 256 257 if ((hint & NOTE_SUBMIT) == 0) 258 mutex_spin_enter(&log_lock); 259 if (msgbufp->msg_bufr == msgbufp->msg_bufx) { 260 rv = 0; 261 } else if (msgbufp->msg_bufr < msgbufp->msg_bufx) { 262 kn->kn_data = msgbufp->msg_bufx - msgbufp->msg_bufr; 263 rv = 1; 264 } else { 265 kn->kn_data = (msgbufp->msg_bufs - msgbufp->msg_bufr) + 266 msgbufp->msg_bufx; 267 rv = 1; 268 } 269 if ((hint & NOTE_SUBMIT) == 0) 270 mutex_spin_exit(&log_lock); 271 272 return rv; 273 } 274 275 static const struct filterops logread_filtops = 276 { 1, NULL, filt_logrdetach, filt_logread }; 277 278 static int 279 logkqfilter(dev_t dev, struct knote *kn) 280 { 281 struct klist *klist; 282 283 switch (kn->kn_filter) { 284 case EVFILT_READ: 285 klist = &log_selp.sel_klist; 286 kn->kn_fop = &logread_filtops; 287 break; 288 289 default: 290 return (EINVAL); 291 } 292 293 mutex_spin_enter(&log_lock); 294 kn->kn_hook = NULL; 295 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 296 mutex_spin_exit(&log_lock); 297 298 return (0); 299 } 300 301 void 302 logwakeup(void) 303 { 304 305 if (!cold && log_open) { 306 mutex_spin_enter(&log_lock); 307 selnotify(&log_selp, 0, NOTE_SUBMIT); 308 if (log_async) 309 softint_schedule(log_sih); 310 cv_broadcast(&log_cv); 311 mutex_spin_exit(&log_lock); 312 } 313 } 314 315 static void 316 logsoftintr(void *cookie) 317 { 318 pid_t pid; 319 320 if ((pid = log_pgid) != 0) 321 fownsignal(pid, SIGIO, 0, 0, NULL); 322 } 323 324 /*ARGSUSED*/ 325 static int 326 logioctl(dev_t dev, u_long com, void *data, int flag, struct lwp *lwp) 327 { 328 long l; 329 330 switch (com) { 331 332 /* return number of characters immediately available */ 333 case FIONREAD: 334 mutex_spin_enter(&log_lock); 335 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 336 if (l < 0) 337 l += msgbufp->msg_bufs; 338 mutex_spin_exit(&log_lock); 339 *(int *)data = l; 340 break; 341 342 case FIONBIO: 343 break; 344 345 case FIOASYNC: 346 /* No locking needed, 'thread private'. */ 347 log_async = (*((int *)data) != 0); 348 break; 349 350 case TIOCSPGRP: 351 case FIOSETOWN: 352 return fsetown(&log_pgid, com, data); 353 354 case TIOCGPGRP: 355 case FIOGETOWN: 356 return fgetown(log_pgid, com, data); 357 358 default: 359 return (EPASSTHROUGH); 360 } 361 return (0); 362 } 363 364 void 365 logputchar(int c) 366 { 367 struct kern_msgbuf *mbp; 368 369 if (!cold) 370 mutex_spin_enter(&log_lock); 371 if (msgbufenabled) { 372 mbp = msgbufp; 373 if (mbp->msg_magic != MSG_MAGIC) { 374 /* 375 * Arguably should panic or somehow notify the 376 * user... but how? Panic may be too drastic, 377 * and would obliterate the message being kicked 378 * out (maybe a panic itself), and printf 379 * would invoke us recursively. Silently punt 380 * for now. If syslog is running, it should 381 * notice. 382 */ 383 msgbufenabled = 0; 384 } else { 385 mbp->msg_bufc[mbp->msg_bufx++] = c; 386 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs) 387 mbp->msg_bufx = 0; 388 /* If the buffer is full, keep the most recent data. */ 389 if (mbp->msg_bufr == mbp->msg_bufx) { 390 if (++mbp->msg_bufr >= mbp->msg_bufs) 391 mbp->msg_bufr = 0; 392 } 393 } 394 } 395 if (!cold) 396 mutex_spin_exit(&log_lock); 397 } 398 399 const struct cdevsw log_cdevsw = { 400 logopen, logclose, logread, nowrite, logioctl, 401 nostop, notty, logpoll, nommap, logkqfilter, 402 D_OTHER | D_MPSAFE 403 }; 404