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