]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
37839358 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
1c79356b | 11 | * |
37839358 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
37839358 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
23 | /* | |
24 | * Copyright (c) 1982, 1986, 1993 | |
25 | * The Regents of the University of California. All rights reserved. | |
26 | * | |
27 | * Redistribution and use in source and binary forms, with or without | |
28 | * modification, are permitted provided that the following conditions | |
29 | * are met: | |
30 | * 1. Redistributions of source code must retain the above copyright | |
31 | * notice, this list of conditions and the following disclaimer. | |
32 | * 2. Redistributions in binary form must reproduce the above copyright | |
33 | * notice, this list of conditions and the following disclaimer in the | |
34 | * documentation and/or other materials provided with the distribution. | |
35 | * 3. All advertising materials mentioning features or use of this software | |
36 | * must display the following acknowledgement: | |
37 | * This product includes software developed by the University of | |
38 | * California, Berkeley and its contributors. | |
39 | * 4. Neither the name of the University nor the names of its contributors | |
40 | * may be used to endorse or promote products derived from this software | |
41 | * without specific prior written permission. | |
42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
44 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
45 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
46 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
47 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
48 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
49 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
51 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
52 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
53 | * SUCH DAMAGE. | |
54 | * | |
55 | * @(#)subr_log.c 8.3 (Berkeley) 2/14/95 | |
56 | */ | |
57 | ||
58 | /* | |
59 | * Error log buffer for kernel printf's. | |
60 | */ | |
61 | ||
62 | #include <sys/param.h> | |
63 | #include <sys/systm.h> | |
91447636 | 64 | #include <sys/proc_internal.h> |
1c79356b A |
65 | #include <sys/vnode.h> |
66 | #include <sys/ioctl.h> | |
67 | #include <sys/msgbuf.h> | |
91447636 | 68 | #include <sys/file_internal.h> |
1c79356b A |
69 | #include <sys/errno.h> |
70 | #include <sys/select.h> | |
91447636 | 71 | #include <sys/kernel.h> |
1c79356b | 72 | #include <kern/thread.h> |
91447636 | 73 | #include <sys/lock.h> |
1c79356b A |
74 | |
75 | #define LOG_RDPRI (PZERO + 1) | |
76 | ||
77 | #define LOG_NBIO 0x02 | |
78 | #define LOG_ASYNC 0x04 | |
79 | #define LOG_RDWAIT 0x08 | |
80 | ||
81 | struct logsoftc { | |
82 | int sc_state; /* see above for possibilities */ | |
83 | struct selinfo sc_selp; /* thread waiting for select */ | |
84 | int sc_pgid; /* process/group for async I/O */ | |
85 | } logsoftc; | |
86 | ||
87 | int log_open; /* also used in log() */ | |
88 | struct msgbuf temp_msgbuf; | |
89 | struct msgbuf *msgbufp; | |
90 | static int _logentrypend = 0; | |
91447636 A |
91 | static int log_inited = 0; |
92 | void bsd_log_lock(void); | |
93 | /* the following two are implemented in osfmk/kern/printf.c */ | |
94 | extern void bsd_log_unlock(void); | |
95 | extern void bsd_log_init(void); | |
1c79356b A |
96 | |
97 | /* | |
98 | * Serialize log access. Note that the log can be written at interrupt level, | |
99 | * so any log manipulations that can be done from, or affect, another processor | |
100 | * at interrupt level must be guarded with a spin lock. | |
101 | */ | |
91447636 A |
102 | |
103 | #define LOG_LOCK() bsd_log_lock() | |
104 | #define LOG_UNLOCK() bsd_log_unlock() | |
105 | ||
1c79356b A |
106 | |
107 | /*ARGSUSED*/ | |
108 | logopen(dev, flags, mode, p) | |
109 | dev_t dev; | |
110 | int flags, mode; | |
111 | struct proc *p; | |
112 | { | |
1c79356b A |
113 | LOG_LOCK(); |
114 | if (log_open) { | |
115 | LOG_UNLOCK(); | |
1c79356b A |
116 | return (EBUSY); |
117 | } | |
118 | log_open = 1; | |
119 | logsoftc.sc_pgid = p->p_pid; /* signal process only */ | |
120 | /* | |
121 | * Potential race here with putchar() but since putchar should be | |
122 | * called by autoconf, msg_magic should be initialized by the time | |
123 | * we get here. | |
124 | */ | |
125 | if (msgbufp->msg_magic != MSG_MAGIC) { | |
126 | register int i; | |
127 | ||
128 | msgbufp->msg_magic = MSG_MAGIC; | |
129 | msgbufp->msg_bufx = msgbufp->msg_bufr = 0; | |
130 | for (i=0; i < MSG_BSIZE; i++) | |
131 | msgbufp->msg_bufc[i] = 0; | |
132 | } | |
133 | LOG_UNLOCK(); | |
9bccf70c | 134 | |
1c79356b A |
135 | return (0); |
136 | } | |
137 | ||
138 | /*ARGSUSED*/ | |
139 | int | |
140 | logclose(dev, flag) | |
141 | dev_t dev; | |
142 | { | |
143 | int oldpri; | |
144 | LOG_LOCK(); | |
145 | log_open = 0; | |
146 | selwakeup(&logsoftc.sc_selp); | |
1c79356b | 147 | selthreadclear(&logsoftc.sc_selp); |
1c79356b A |
148 | LOG_UNLOCK(); |
149 | return (0); | |
150 | } | |
151 | ||
152 | /*ARGSUSED*/ | |
153 | int | |
154 | logread(dev, uio, flag) | |
155 | dev_t dev; | |
156 | struct uio *uio; | |
157 | int flag; | |
158 | { | |
159 | register long l; | |
160 | register int s; | |
161 | int error = 0; | |
91447636 A |
162 | char localbuff[MSG_BSIZE]; |
163 | int copybytes; | |
1c79356b | 164 | |
91447636 | 165 | LOG_LOCK(); |
1c79356b A |
166 | while (msgbufp->msg_bufr == msgbufp->msg_bufx) { |
167 | if (flag & IO_NDELAY) { | |
91447636 A |
168 | error = EWOULDBLOCK; |
169 | goto out; | |
1c79356b A |
170 | } |
171 | if (logsoftc.sc_state & LOG_NBIO) { | |
91447636 A |
172 | error = EWOULDBLOCK; |
173 | goto out; | |
1c79356b A |
174 | } |
175 | logsoftc.sc_state |= LOG_RDWAIT; | |
91447636 A |
176 | LOG_UNLOCK(); |
177 | /* | |
178 | * If the wakeup is missed the ligtening bolt will wake this up | |
179 | * if there are any new characters. If that doesn't do it | |
180 | * then wait for 5 sec and reevaluate | |
181 | */ | |
1c79356b | 182 | if (error = tsleep((caddr_t)msgbufp, LOG_RDPRI | PCATCH, |
91447636 A |
183 | "klog", 5 * hz)) { |
184 | /* if it times out; ignore */ | |
185 | if (error != EWOULDBLOCK) | |
186 | return (error); | |
1c79356b | 187 | } |
91447636 | 188 | LOG_LOCK(); |
1c79356b | 189 | } |
1c79356b A |
190 | logsoftc.sc_state &= ~LOG_RDWAIT; |
191 | ||
91447636 A |
192 | |
193 | while (uio_resid(uio) > 0) { | |
1c79356b A |
194 | l = msgbufp->msg_bufx - msgbufp->msg_bufr; |
195 | if (l < 0) | |
196 | l = MSG_BSIZE - msgbufp->msg_bufr; | |
91447636 | 197 | l = min(l, uio_resid(uio)); |
1c79356b A |
198 | if (l == 0) |
199 | break; | |
91447636 A |
200 | bcopy(&msgbufp->msg_bufc[msgbufp->msg_bufr], &localbuff[0], l); |
201 | LOG_UNLOCK(); | |
202 | error = uiomove((caddr_t)&localbuff[0], | |
1c79356b | 203 | (int)l, uio); |
91447636 | 204 | LOG_LOCK(); |
1c79356b A |
205 | if (error) |
206 | break; | |
207 | msgbufp->msg_bufr += l; | |
208 | if (msgbufp->msg_bufr < 0 || msgbufp->msg_bufr >= MSG_BSIZE) | |
209 | msgbufp->msg_bufr = 0; | |
210 | } | |
91447636 A |
211 | out: |
212 | LOG_UNLOCK(); | |
1c79356b A |
213 | return (error); |
214 | } | |
215 | ||
216 | /*ARGSUSED*/ | |
217 | int | |
0b4e3aa0 | 218 | logselect(dev, rw, wql, p) |
1c79356b A |
219 | dev_t dev; |
220 | int rw; | |
0b4e3aa0 | 221 | void * wql; |
1c79356b A |
222 | struct proc *p; |
223 | { | |
1c79356b A |
224 | |
225 | switch (rw) { | |
226 | ||
227 | case FREAD: | |
91447636 | 228 | LOG_LOCK(); |
1c79356b | 229 | if (msgbufp->msg_bufr != msgbufp->msg_bufx) { |
91447636 | 230 | LOG_UNLOCK(); |
1c79356b A |
231 | return (1); |
232 | } | |
0b4e3aa0 | 233 | selrecord(p, &logsoftc.sc_selp, wql); |
91447636 | 234 | LOG_UNLOCK(); |
1c79356b A |
235 | break; |
236 | } | |
1c79356b A |
237 | return (0); |
238 | } | |
239 | ||
240 | void | |
241 | logwakeup() | |
242 | { | |
243 | struct proc *p; | |
244 | int pgid; | |
245 | boolean_t funnel_state; | |
246 | ||
91447636 A |
247 | LOG_LOCK(); |
248 | if (!log_open) { | |
249 | LOG_UNLOCK(); | |
1c79356b | 250 | return; |
91447636 | 251 | } |
1c79356b A |
252 | selwakeup(&logsoftc.sc_selp); |
253 | if (logsoftc.sc_state & LOG_ASYNC) { | |
1c79356b A |
254 | pgid = logsoftc.sc_pgid; |
255 | LOG_UNLOCK(); | |
256 | if (pgid < 0) | |
257 | gsignal(-pgid, SIGIO); | |
258 | else if (p = pfind(pgid)) | |
259 | psignal(p, SIGIO); | |
91447636 | 260 | LOG_LOCK(); |
1c79356b A |
261 | } |
262 | if (logsoftc.sc_state & LOG_RDWAIT) { | |
263 | wakeup((caddr_t)msgbufp); | |
264 | logsoftc.sc_state &= ~LOG_RDWAIT; | |
265 | } | |
91447636 | 266 | LOG_UNLOCK(); |
1c79356b A |
267 | } |
268 | ||
269 | void | |
270 | klogwakeup() | |
271 | { | |
272 | ||
273 | if (_logentrypend) { | |
274 | _logentrypend = 0; | |
275 | logwakeup(); | |
276 | } | |
277 | } | |
278 | ||
279 | /*ARGSUSED*/ | |
280 | int | |
55e303ae | 281 | logioctl(dev, com, data, flag) |
1c79356b A |
282 | caddr_t data; |
283 | { | |
284 | long l; | |
285 | int s; | |
286 | ||
91447636 | 287 | LOG_LOCK(); |
1c79356b A |
288 | switch (com) { |
289 | ||
290 | /* return number of characters immediately available */ | |
291 | case FIONREAD: | |
1c79356b | 292 | l = msgbufp->msg_bufx - msgbufp->msg_bufr; |
1c79356b A |
293 | if (l < 0) |
294 | l += MSG_BSIZE; | |
295 | *(off_t *)data = l; | |
296 | break; | |
297 | ||
298 | case FIONBIO: | |
299 | if (*(int *)data) | |
300 | logsoftc.sc_state |= LOG_NBIO; | |
301 | else | |
302 | logsoftc.sc_state &= ~LOG_NBIO; | |
303 | break; | |
304 | ||
305 | case FIOASYNC: | |
306 | if (*(int *)data) | |
307 | logsoftc.sc_state |= LOG_ASYNC; | |
308 | else | |
309 | logsoftc.sc_state &= ~LOG_ASYNC; | |
310 | break; | |
311 | ||
312 | case TIOCSPGRP: | |
1c79356b | 313 | logsoftc.sc_pgid = *(int *)data; |
1c79356b A |
314 | break; |
315 | ||
316 | case TIOCGPGRP: | |
1c79356b | 317 | *(int *)data = logsoftc.sc_pgid; |
1c79356b A |
318 | break; |
319 | ||
320 | default: | |
91447636 | 321 | LOG_UNLOCK(); |
1c79356b A |
322 | return (-1); |
323 | } | |
91447636 | 324 | LOG_UNLOCK(); |
1c79356b A |
325 | return (0); |
326 | } | |
327 | ||
328 | void | |
91447636 | 329 | bsd_log_init() |
1c79356b | 330 | { |
91447636 A |
331 | if (!log_inited) { |
332 | msgbufp = &temp_msgbuf; | |
333 | log_inited = 1; | |
334 | } | |
1c79356b A |
335 | } |
336 | ||
337 | void | |
338 | log_putc(char c) | |
339 | { | |
340 | register struct msgbuf *mbp; | |
341 | ||
91447636 A |
342 | if (!log_inited) { |
343 | panic("bsd log is not inited"); | |
344 | } | |
345 | LOG_LOCK(); | |
1c79356b A |
346 | |
347 | mbp = msgbufp; | |
348 | if (mbp-> msg_magic != MSG_MAGIC) { | |
349 | register int i; | |
350 | ||
351 | mbp->msg_magic = MSG_MAGIC; | |
352 | mbp->msg_bufx = mbp->msg_bufr = 0; | |
353 | for (i=0; i < MSG_BSIZE; i++) | |
354 | mbp->msg_bufc[i] = 0; | |
355 | } | |
356 | mbp->msg_bufc[mbp->msg_bufx++] = c; | |
357 | _logentrypend = 1; | |
358 | if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) | |
359 | mbp->msg_bufx = 0; | |
91447636 | 360 | LOG_UNLOCK(); |
1c79356b | 361 | } |
91447636 | 362 |