root/kern/subr_log.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. initmsgbuf
  2. msgbuf_putchar
  3. logopen
  4. logclose
  5. logread
  6. logpoll
  7. logkqfilter
  8. filt_logrdetach
  9. filt_logread
  10. logwakeup
  11. logioctl

    1 /*      $OpenBSD: subr_log.c,v 1.14 2005/12/09 09:09:52 jsg 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 
   56 struct 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 
   64 int     log_open;                       /* also used in log() */
   65 int     msgbufmapped;                   /* is the message buffer mapped */
   66 int     msgbufenabled;                  /* is logging to the buffer enabled */
   67 struct  msgbuf *msgbufp;                /* the mapped buffer, itself. */
   68 
   69 void filt_logrdetach(struct knote *kn);
   70 int filt_logread(struct knote *kn, long hint);
   71    
   72 struct filterops logread_filtops =
   73         { 1, NULL, filt_logrdetach, filt_logread};
   74 
   75 void
   76 initmsgbuf(caddr_t buf, size_t bufsize)
   77 {
   78         struct msgbuf *mbp;
   79         long new_bufs;
   80 
   81         /* Sanity-check the given size. */
   82         if (bufsize < sizeof(struct msgbuf))
   83                 return;
   84 
   85         mbp = msgbufp = (struct msgbuf *)buf;
   86 
   87         new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc);
   88         if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) ||
   89             (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) ||
   90             (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) {
   91                 /*
   92                  * If the buffer magic number is wrong, has changed
   93                  * size (which shouldn't happen often), or is
   94                  * internally inconsistent, initialize it.
   95                  */
   96 
   97                 bzero(buf, bufsize);
   98                 mbp->msg_magic = MSG_MAGIC;
   99                 mbp->msg_bufs = new_bufs;
  100         }
  101         
  102         /* Always start new buffer data on a new line. */
  103         if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n')
  104                 msgbuf_putchar('\n');
  105 
  106         /* mark it as ready for use. */
  107         msgbufmapped = msgbufenabled = 1;
  108 }
  109 
  110 void
  111 msgbuf_putchar(const char c) 
  112 {
  113         struct msgbuf *mbp = msgbufp;
  114 
  115         if (mbp->msg_magic != MSG_MAGIC)
  116                 /* Nothing we can do */
  117                 return;
  118 
  119         mbp->msg_bufc[mbp->msg_bufx++] = c;
  120         mbp->msg_bufl = min(mbp->msg_bufl+1, mbp->msg_bufs);
  121         if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs)
  122                 mbp->msg_bufx = 0;
  123         /* If the buffer is full, keep the most recent data. */
  124         if (mbp->msg_bufr == mbp->msg_bufx) {
  125                 if (++mbp->msg_bufr >= mbp->msg_bufs)
  126                         mbp->msg_bufr = 0;
  127         }
  128 }
  129 
  130 /*ARGSUSED*/
  131 int
  132 logopen(dev_t dev, int flags, int mode, struct proc *p)
  133 {
  134         if (log_open)
  135                 return (EBUSY);
  136         log_open = 1;
  137         return (0);
  138 }
  139 
  140 /*ARGSUSED*/
  141 int
  142 logclose(dev_t dev, int flag, int mode, struct proc *p)
  143 {
  144 
  145         log_open = 0;
  146         logsoftc.sc_state = 0;
  147         return (0);
  148 }
  149 
  150 /*ARGSUSED*/
  151 int
  152 logread(dev_t dev, struct uio *uio, int flag)
  153 {
  154         struct msgbuf *mbp = msgbufp;
  155         long l;
  156         int s;
  157         int error = 0;
  158 
  159         s = splhigh();
  160         while (mbp->msg_bufr == mbp->msg_bufx) {
  161                 if (flag & IO_NDELAY) {
  162                         splx(s);
  163                         return (EWOULDBLOCK);
  164                 }
  165                 logsoftc.sc_state |= LOG_RDWAIT;
  166                 error = tsleep(mbp, LOG_RDPRI | PCATCH,
  167                                "klog", 0);
  168                 if (error) {
  169                         splx(s);
  170                         return (error);
  171                 }
  172         }
  173         splx(s);
  174         logsoftc.sc_state &= ~LOG_RDWAIT;
  175 
  176         while (uio->uio_resid > 0) {
  177                 l = mbp->msg_bufx - mbp->msg_bufr;
  178                 if (l < 0)
  179                         l = mbp->msg_bufs - mbp->msg_bufr;
  180                 l = min(l, uio->uio_resid);
  181                 if (l == 0)
  182                         break;
  183                 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], (int)l, uio);
  184                 if (error)
  185                         break;
  186                 mbp->msg_bufr += l;
  187                 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs)
  188                         mbp->msg_bufr = 0;
  189         }
  190         return (error);
  191 }
  192 
  193 /*ARGSUSED*/
  194 int
  195 logpoll(dev_t dev, int events, struct proc *p)
  196 {
  197         int revents = 0;
  198         int s = splhigh();
  199 
  200         if (events & (POLLIN | POLLRDNORM)) {
  201                 if (msgbufp->msg_bufr != msgbufp->msg_bufx)
  202                         revents |= events & (POLLIN | POLLRDNORM);
  203                 else
  204                         selrecord(p, &logsoftc.sc_selp);
  205         }
  206         splx(s);
  207         return (revents);
  208 }
  209 
  210 int
  211 logkqfilter(dev_t dev, struct knote *kn)
  212 {
  213         struct klist *klist;
  214         int s;
  215 
  216         switch (kn->kn_filter) {
  217         case EVFILT_READ:
  218                 klist = &logsoftc.sc_selp.si_note;
  219                 kn->kn_fop = &logread_filtops;
  220                 break;
  221         default:
  222                 return (1);
  223         }
  224 
  225         kn->kn_hook = (void *)msgbufp;
  226 
  227         s = splhigh();
  228         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  229         splx(s);
  230 
  231         return (0);
  232 }
  233 
  234 void
  235 filt_logrdetach(struct knote *kn)
  236 {
  237         int s = splhigh();
  238 
  239         SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext);
  240         splx(s);
  241 }
  242 
  243 int
  244 filt_logread(struct knote *kn, long hint)
  245 {
  246         struct  msgbuf *p = (struct  msgbuf *)kn->kn_hook;
  247 
  248         kn->kn_data = (int)(p->msg_bufx - p->msg_bufr);
  249 
  250         return (p->msg_bufx != p->msg_bufr);
  251 }
  252 
  253 void
  254 logwakeup(void)
  255 {
  256         if (!log_open)
  257                 return;
  258         selwakeup(&logsoftc.sc_selp);
  259         if (logsoftc.sc_state & LOG_ASYNC)
  260                 csignal(logsoftc.sc_pgid, SIGIO,
  261                     logsoftc.sc_siguid, logsoftc.sc_sigeuid);
  262         if (logsoftc.sc_state & LOG_RDWAIT) {
  263                 wakeup(msgbufp);
  264                 logsoftc.sc_state &= ~LOG_RDWAIT;
  265         }
  266         KNOTE(&logsoftc.sc_selp.si_note, 0);
  267 }
  268 
  269 /*ARGSUSED*/
  270 int
  271 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p)
  272 {
  273         long l;
  274         int s;
  275 
  276         switch (com) {
  277 
  278         /* return number of characters immediately available */
  279         case FIONREAD:
  280                 s = splhigh();
  281                 l = msgbufp->msg_bufx - msgbufp->msg_bufr;
  282                 splx(s);
  283                 if (l < 0)
  284                         l += msgbufp->msg_bufs;
  285                 *(int *)data = l;
  286                 break;
  287 
  288         case FIONBIO:
  289                 break;
  290 
  291         case FIOASYNC:
  292                 if (*(int *)data)
  293                         logsoftc.sc_state |= LOG_ASYNC;
  294                 else
  295                         logsoftc.sc_state &= ~LOG_ASYNC;
  296                 break;
  297 
  298         case TIOCSPGRP:
  299                 logsoftc.sc_pgid = *(int *)data;
  300                 logsoftc.sc_siguid = p->p_cred->p_ruid;
  301                 logsoftc.sc_sigeuid = p->p_ucred->cr_uid;
  302                 break;
  303 
  304         case TIOCGPGRP:
  305                 *(int *)data = logsoftc.sc_pgid;
  306                 break;
  307 
  308         default:
  309                 return (-1);
  310         }
  311         return (0);
  312 }

/* [<][>][^][v][top][bottom][index][help] */