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