Commit | Line | Data |
---|---|---|
984263bc MD |
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. | |
dc71b7ab | 13 | * 3. Neither the name of the University nor the names of its contributors |
984263bc MD |
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> | |
13dd34d8 | 39 | #include <sys/uio.h> |
984263bc | 40 | #include <sys/conf.h> |
fef8985e | 41 | #include <sys/device.h> |
984263bc MD |
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> | |
fef8f01a | 49 | #include <sys/event.h> |
984263bc MD |
50 | #include <sys/filedesc.h> |
51 | #include <sys/sysctl.h> | |
e43a034f | 52 | #include <sys/thread2.h> |
984263bc | 53 | |
984263bc MD |
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; | |
fef8f01a | 61 | static d_kqfilter_t logkqfilter; |
984263bc MD |
62 | |
63 | static void logtimeout(void *arg); | |
fef8f01a SG |
64 | static void logfiltdetach(struct knote *kn); |
65 | static int logfiltread(struct knote *kn, long hint); | |
984263bc MD |
66 | |
67 | #define CDEV_MAJOR 7 | |
fef8985e | 68 | static struct dev_ops log_ops = { |
88abd8b5 | 69 | { "log", 0, 0 }, |
fef8985e MD |
70 | .d_open = logopen, |
71 | .d_close = logclose, | |
72 | .d_read = logread, | |
73 | .d_ioctl = logioctl, | |
fef8f01a | 74 | .d_kqfilter = logkqfilter |
984263bc MD |
75 | }; |
76 | ||
77 | static struct logsoftc { | |
78 | int sc_state; /* see above for possibilities */ | |
5b22f1a7 | 79 | struct kqinfo sc_kqp; /* processes waiting on I/O */ |
984263bc MD |
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 | |
fef8985e | 93 | logopen(struct dev_open_args *ap) |
984263bc | 94 | { |
fef8985e | 95 | struct proc *p = curproc; |
41c20dac MD |
96 | |
97 | KKASSERT(p != NULL); | |
984263bc MD |
98 | if (log_open) |
99 | return (EBUSY); | |
100 | log_open = 1; | |
bf0ecf68 | 101 | callout_init_mp(&logsoftc.sc_callout); |
984263bc MD |
102 | fsetown(p->p_pid, &logsoftc.sc_sigio); /* signal process only */ |
103 | callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, | |
bf0ecf68 | 104 | logtimeout, NULL); |
984263bc MD |
105 | return (0); |
106 | } | |
107 | ||
108 | /*ARGSUSED*/ | |
109 | static int | |
fef8985e | 110 | logclose(struct dev_close_args *ap) |
984263bc | 111 | { |
984263bc | 112 | log_open = 0; |
eb67213a | 113 | callout_cancel(&logsoftc.sc_callout); |
984263bc | 114 | logsoftc.sc_state = 0; |
58c2553a | 115 | funsetown(&logsoftc.sc_sigio); |
984263bc MD |
116 | return (0); |
117 | } | |
118 | ||
119 | /*ARGSUSED*/ | |
120 | static int | |
fef8985e | 121 | logread(struct dev_read_args *ap) |
984263bc | 122 | { |
fef8985e | 123 | struct uio *uio = ap->a_uio; |
984263bc | 124 | struct msgbuf *mbp = msgbufp; |
984263bc | 125 | int error = 0; |
5608ef17 MD |
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(); | |
fef8985e | 136 | if (ap->a_ioflag & IO_NDELAY) { |
e43a034f | 137 | crit_exit(); |
984263bc MD |
138 | return (EWOULDBLOCK); |
139 | } | |
5608ef17 | 140 | atomic_set_int(&logsoftc.sc_state, LOG_RDWAIT); |
377d4740 | 141 | if ((error = tsleep((caddr_t)mbp, PCATCH, "klog", 0))) { |
e43a034f | 142 | crit_exit(); |
984263bc MD |
143 | return (error); |
144 | } | |
5608ef17 MD |
145 | /* don't bother clearing LOG_RDWAIT */ |
146 | crit_exit(); | |
984263bc | 147 | } |
5608ef17 MD |
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); | |
984263bc MD |
183 | if (error) |
184 | break; | |
5608ef17 | 185 | mbp->msg_bufl = lindex + n; |
984263bc MD |
186 | } |
187 | return (error); | |
188 | } | |
189 | ||
fef8f01a | 190 | static struct filterops logread_filtops = |
4c91dbc9 | 191 | { FILTEROP_ISFD, NULL, logfiltdetach, logfiltread }; |
fef8f01a SG |
192 | |
193 | static int | |
194 | logkqfilter(struct dev_kqfilter_args *ap) | |
195 | { | |
196 | struct knote *kn = ap->a_kn; | |
5b22f1a7 | 197 | struct klist *klist = &logsoftc.sc_kqp.ki_note; |
fef8f01a SG |
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: | |
b287d649 | 205 | ap->a_result = EOPNOTSUPP; |
fef8f01a SG |
206 | return (0); |
207 | } | |
208 | ||
5b22f1a7 | 209 | knote_insert(klist, kn); |
fef8f01a SG |
210 | |
211 | return (0); | |
212 | } | |
213 | ||
214 | static void | |
215 | logfiltdetach(struct knote *kn) | |
216 | { | |
5b22f1a7 | 217 | struct klist *klist = &logsoftc.sc_kqp.ki_note; |
fef8f01a | 218 | |
5b22f1a7 | 219 | knote_remove(klist, kn); |
fef8f01a SG |
220 | } |
221 | ||
222 | static int | |
223 | logfiltread(struct knote *kn, long hint) | |
224 | { | |
225 | int ret = 0; | |
226 | ||
227 | crit_enter(); | |
5608ef17 | 228 | if (msgbufp->msg_bufl != msgbufp->msg_bufx) |
fef8f01a SG |
229 | ret = 1; |
230 | crit_exit(); | |
231 | ||
232 | return (ret); | |
233 | } | |
234 | ||
984263bc MD |
235 | static void |
236 | logtimeout(void *arg) | |
237 | { | |
984263bc MD |
238 | if (!log_open) |
239 | return; | |
240 | if (msgbuftrigger == 0) { | |
241 | callout_reset(&logsoftc.sc_callout, | |
bf0ecf68 | 242 | hz / log_wakeups_per_second, logtimeout, NULL); |
984263bc MD |
243 | return; |
244 | } | |
245 | msgbuftrigger = 0; | |
5b22f1a7 | 246 | KNOTE(&logsoftc.sc_kqp.ki_note, 0); |
984263bc MD |
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) { | |
5608ef17 | 250 | atomic_clear_int(&logsoftc.sc_state, LOG_RDWAIT); |
984263bc | 251 | wakeup((caddr_t)msgbufp); |
984263bc MD |
252 | } |
253 | callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second, | |
bf0ecf68 | 254 | logtimeout, NULL); |
984263bc MD |
255 | } |
256 | ||
257 | /*ARGSUSED*/ | |
258 | static int | |
fef8985e | 259 | logioctl(struct dev_ioctl_args *ap) |
984263bc | 260 | { |
5608ef17 MD |
261 | struct msgbuf *mbp = msgbufp; |
262 | u_int lindex; | |
263 | u_int xindex; | |
264 | u_int n; | |
984263bc | 265 | |
fef8985e | 266 | switch (ap->a_cmd) { |
984263bc | 267 | case FIONREAD: |
5608ef17 MD |
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; | |
984263bc MD |
283 | break; |
284 | ||
984263bc | 285 | case FIOASYNC: |
fef8985e | 286 | if (*(int *)ap->a_data) |
5608ef17 | 287 | atomic_set_int(&logsoftc.sc_state, LOG_ASYNC); |
984263bc | 288 | else |
5608ef17 | 289 | atomic_clear_int(&logsoftc.sc_state, LOG_ASYNC); |
984263bc MD |
290 | break; |
291 | ||
292 | case FIOSETOWN: | |
fef8985e | 293 | return (fsetown(*(int *)ap->a_data, &logsoftc.sc_sigio)); |
984263bc MD |
294 | |
295 | case FIOGETOWN: | |
b5c4d81f | 296 | *(int *)ap->a_data = fgetown(&logsoftc.sc_sigio); |
984263bc MD |
297 | break; |
298 | ||
299 | /* This is deprecated, FIOSETOWN should be used instead. */ | |
300 | case TIOCSPGRP: | |
fef8985e | 301 | return (fsetown(-(*(int *)ap->a_data), &logsoftc.sc_sigio)); |
984263bc MD |
302 | |
303 | /* This is deprecated, FIOGETOWN should be used instead */ | |
304 | case TIOCGPGRP: | |
b5c4d81f | 305 | *(int *)ap->a_data = -fgetown(&logsoftc.sc_sigio); |
984263bc MD |
306 | break; |
307 | ||
308 | default: | |
309 | return (ENOTTY); | |
310 | } | |
311 | return (0); | |
312 | } | |
313 | ||
314 | static void | |
315 | log_drvinit(void *unused) | |
316 | { | |
fef8985e | 317 | make_dev(&log_ops, 0, UID_ROOT, GID_WHEEL, 0600, "klog"); |
984263bc MD |
318 | } |
319 | ||
f3f3eadb SW |
320 | SYSINIT(logdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, log_drvinit, |
321 | NULL); |