]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/subr_log.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / bsd / kern / subr_log.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1982, 1986, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)subr_log.c 8.3 (Berkeley) 2/14/95
62 */
63
64/*
65 * Error log buffer for kernel printf's.
66 */
67
68#include <sys/param.h>
69#include <sys/systm.h>
91447636 70#include <sys/proc_internal.h>
1c79356b
A
71#include <sys/vnode.h>
72#include <sys/ioctl.h>
73#include <sys/msgbuf.h>
91447636 74#include <sys/file_internal.h>
1c79356b
A
75#include <sys/errno.h>
76#include <sys/select.h>
91447636 77#include <sys/kernel.h>
1c79356b 78#include <kern/thread.h>
91447636 79#include <sys/lock.h>
2d21ac55
A
80#include <sys/signalvar.h>
81#include <sys/conf.h>
82#include <sys/sysctl.h>
83#include <kern/kalloc.h>
84
85/* XXX should be in a common header somewhere */
86extern void klogwakeup(void);
87extern void logwakeup(void);
1c79356b
A
88
89#define LOG_RDPRI (PZERO + 1)
90
91#define LOG_NBIO 0x02
92#define LOG_ASYNC 0x04
93#define LOG_RDWAIT 0x08
94
95struct logsoftc {
96 int sc_state; /* see above for possibilities */
97 struct selinfo sc_selp; /* thread waiting for select */
98 int sc_pgid; /* process/group for async I/O */
99} logsoftc;
100
101int log_open; /* also used in log() */
2d21ac55
A
102char smsg_bufc[MSG_BSIZE]; /* static buffer */
103struct msgbuf temp_msgbuf = {0,MSG_BSIZE,0,0,smsg_bufc};
1c79356b
A
104struct msgbuf *msgbufp;
105static int _logentrypend = 0;
91447636 106static int log_inited = 0;
2d21ac55
A
107/* the following are implemented in osfmk/kern/printf.c */
108extern void bsd_log_lock(void);
91447636
A
109extern void bsd_log_unlock(void);
110extern void bsd_log_init(void);
1c79356b 111
2d21ac55
A
112/* XXX wants a linker set so these can be static */
113extern d_open_t logopen;
114extern d_close_t logclose;
115extern d_read_t logread;
116extern d_ioctl_t logioctl;
117extern d_select_t logselect;
118
1c79356b
A
119/*
120 * Serialize log access. Note that the log can be written at interrupt level,
121 * so any log manipulations that can be done from, or affect, another processor
122 * at interrupt level must be guarded with a spin lock.
123 */
91447636
A
124
125#define LOG_LOCK() bsd_log_lock()
126#define LOG_UNLOCK() bsd_log_unlock()
127
1c79356b
A
128
129/*ARGSUSED*/
2d21ac55
A
130int
131logopen(__unused dev_t dev, __unused int flags, __unused int mode, struct proc *p)
1c79356b 132{
1c79356b
A
133 LOG_LOCK();
134 if (log_open) {
135 LOG_UNLOCK();
1c79356b
A
136 return (EBUSY);
137 }
138 log_open = 1;
139 logsoftc.sc_pgid = p->p_pid; /* signal process only */
140 /*
141 * Potential race here with putchar() but since putchar should be
142 * called by autoconf, msg_magic should be initialized by the time
143 * we get here.
144 */
145 if (msgbufp->msg_magic != MSG_MAGIC) {
146 register int i;
147
148 msgbufp->msg_magic = MSG_MAGIC;
149 msgbufp->msg_bufx = msgbufp->msg_bufr = 0;
150 for (i=0; i < MSG_BSIZE; i++)
151 msgbufp->msg_bufc[i] = 0;
152 }
153 LOG_UNLOCK();
9bccf70c 154
1c79356b
A
155 return (0);
156}
157
158/*ARGSUSED*/
159int
2d21ac55 160logclose(__unused dev_t dev, __unused int flag, __unused int devtype, __unused struct proc *p)
1c79356b 161{
1c79356b
A
162 LOG_LOCK();
163 log_open = 0;
164 selwakeup(&logsoftc.sc_selp);
1c79356b 165 selthreadclear(&logsoftc.sc_selp);
1c79356b
A
166 LOG_UNLOCK();
167 return (0);
168}
169
170/*ARGSUSED*/
171int
2d21ac55 172logread(__unused dev_t dev, struct uio *uio, int flag)
1c79356b
A
173{
174 register long l;
1c79356b
A
175 int error = 0;
176
91447636 177 LOG_LOCK();
1c79356b
A
178 while (msgbufp->msg_bufr == msgbufp->msg_bufx) {
179 if (flag & IO_NDELAY) {
91447636
A
180 error = EWOULDBLOCK;
181 goto out;
1c79356b
A
182 }
183 if (logsoftc.sc_state & LOG_NBIO) {
91447636
A
184 error = EWOULDBLOCK;
185 goto out;
1c79356b
A
186 }
187 logsoftc.sc_state |= LOG_RDWAIT;
91447636
A
188 LOG_UNLOCK();
189 /*
190 * If the wakeup is missed the ligtening bolt will wake this up
191 * if there are any new characters. If that doesn't do it
192 * then wait for 5 sec and reevaluate
193 */
2d21ac55
A
194 if ((error = tsleep((caddr_t)msgbufp, LOG_RDPRI | PCATCH,
195 "klog", 5 * hz)) != 0) {
91447636
A
196 /* if it times out; ignore */
197 if (error != EWOULDBLOCK)
198 return (error);
1c79356b 199 }
91447636 200 LOG_LOCK();
1c79356b 201 }
1c79356b
A
202 logsoftc.sc_state &= ~LOG_RDWAIT;
203
91447636 204 while (uio_resid(uio) > 0) {
1c79356b
A
205 l = msgbufp->msg_bufx - msgbufp->msg_bufr;
206 if (l < 0)
2d21ac55 207 l = msgbufp->msg_size - msgbufp->msg_bufr;
91447636 208 l = min(l, uio_resid(uio));
1c79356b
A
209 if (l == 0)
210 break;
91447636 211 LOG_UNLOCK();
2d21ac55 212 error = uiomove((caddr_t)&msgbufp->msg_bufc[msgbufp->msg_bufr],
1c79356b 213 (int)l, uio);
91447636 214 LOG_LOCK();
1c79356b
A
215 if (error)
216 break;
217 msgbufp->msg_bufr += l;
2d21ac55 218 if (msgbufp->msg_bufr < 0 || msgbufp->msg_bufr >= msgbufp->msg_size)
1c79356b
A
219 msgbufp->msg_bufr = 0;
220 }
91447636
A
221out:
222 LOG_UNLOCK();
1c79356b
A
223 return (error);
224}
225
226/*ARGSUSED*/
227int
2d21ac55 228logselect(__unused dev_t dev, int rw, void * wql, struct proc *p)
1c79356b 229{
1c79356b
A
230 switch (rw) {
231
232 case FREAD:
91447636 233 LOG_LOCK();
1c79356b 234 if (msgbufp->msg_bufr != msgbufp->msg_bufx) {
91447636 235 LOG_UNLOCK();
1c79356b
A
236 return (1);
237 }
0b4e3aa0 238 selrecord(p, &logsoftc.sc_selp, wql);
91447636 239 LOG_UNLOCK();
1c79356b
A
240 break;
241 }
1c79356b
A
242 return (0);
243}
244
245void
2d21ac55 246logwakeup(void)
1c79356b 247{
1c79356b 248 int pgid;
1c79356b 249
91447636
A
250 LOG_LOCK();
251 if (!log_open) {
252 LOG_UNLOCK();
1c79356b 253 return;
91447636 254 }
1c79356b
A
255 selwakeup(&logsoftc.sc_selp);
256 if (logsoftc.sc_state & LOG_ASYNC) {
1c79356b
A
257 pgid = logsoftc.sc_pgid;
258 LOG_UNLOCK();
259 if (pgid < 0)
260 gsignal(-pgid, SIGIO);
2d21ac55
A
261 else
262 proc_signal(pgid, SIGIO);
91447636 263 LOG_LOCK();
1c79356b
A
264 }
265 if (logsoftc.sc_state & LOG_RDWAIT) {
266 wakeup((caddr_t)msgbufp);
267 logsoftc.sc_state &= ~LOG_RDWAIT;
268 }
91447636 269 LOG_UNLOCK();
1c79356b
A
270}
271
272void
2d21ac55 273klogwakeup(void)
1c79356b 274{
1c79356b
A
275 if (_logentrypend) {
276 _logentrypend = 0;
277 logwakeup();
278 }
279}
280
281/*ARGSUSED*/
282int
2d21ac55 283logioctl(__unused dev_t dev, u_long com, caddr_t data, __unused int flag, __unused struct proc *p)
1c79356b
A
284{
285 long l;
1c79356b 286
2d21ac55 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 293 if (l < 0)
2d21ac55 294 l += msgbufp->msg_size;
1c79356b
A
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
328void
2d21ac55 329bsd_log_init(void)
1c79356b 330{
91447636
A
331 if (!log_inited) {
332 msgbufp = &temp_msgbuf;
333 log_inited = 1;
334 }
1c79356b
A
335}
336
2d21ac55
A
337
338/*
339 * log_putc_locked
340 *
341 * Decription: Output a character to the log; assumes the LOG_LOCK() is held
342 * by the caller.
343 *
344 * Parameters: c Character to output
345 *
346 * Returns: (void)
347 *
348 * Notes: This functions is used for multibyte output to the log; it
349 * should be used preferrentially where possible to ensure that
350 * log entries do not end up interspersed due to preemption or
351 * SMP reentrancy.
352 */
1c79356b 353void
2d21ac55 354log_putc_locked(char c)
1c79356b
A
355{
356 register struct msgbuf *mbp;
357
91447636
A
358 if (!log_inited) {
359 panic("bsd log is not inited");
360 }
1c79356b
A
361
362 mbp = msgbufp;
2d21ac55 363 if (mbp-> msg_magic != MSG_MAGIC) {
1c79356b
A
364 register int i;
365
366 mbp->msg_magic = MSG_MAGIC;
367 mbp->msg_bufx = mbp->msg_bufr = 0;
368 for (i=0; i < MSG_BSIZE; i++)
369 mbp->msg_bufc[i] = 0;
370 }
371 mbp->msg_bufc[mbp->msg_bufx++] = c;
372 _logentrypend = 1;
2d21ac55 373 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= msgbufp->msg_size)
1c79356b 374 mbp->msg_bufx = 0;
2d21ac55
A
375}
376
377
378/*
379 * log_putc
380 *
381 * Decription: Output a character to the log; assumes the LOG_LOCK() is NOT
382 * held by the caller.
383 *
384 * Parameters: c Character to output
385 *
386 * Returns: (void)
387 *
388 * Notes: This function is used for syingle byte output to the log. It
389 * primarily exists to maintain binary backward compatibility.
390 */
391void
392log_putc(char c)
393{
394 if (!log_inited) {
395 panic("bsd log is not inited");
396 }
397 LOG_LOCK();
398 log_putc_locked(c);
91447636 399 LOG_UNLOCK();
1c79356b 400}
91447636 401
2d21ac55
A
402
403/*
404 * it is possible to increase the kernel log buffer size by adding
405 * msgbuf=n
406 * to the kernel command line, and to read the current size using
407 * sysctl kern.msgbuf
408 * If there is no parameter on the kernel command line, the buffer is
409 * allocated statically and is MSG_BSIZE characters in size, otherwise
410 * memory is dynamically allocated.
411 * This function may only be called once, during kernel initialization.
412 * Memory management must already be up. The buffer must not have
413 * overflown yet.
414 */
415void
416log_setsize(long size) {
417 char *new_logdata;
418 if (msgbufp->msg_size!=MSG_BSIZE) {
419 printf("log_setsize: attempt to change size more than once\n");
420 return;
421 }
422 if (size==MSG_BSIZE)
423 return;
424 if (size<MSG_BSIZE) { /* we don't support reducing the log size */
425 printf("log_setsize: can't decrease log size\n");
426 return;
427 }
428 if (!(new_logdata = (char*)kalloc(size))) {
429 printf("log_setsize: unable to allocate memory\n");
430 return;
431 }
432 LOG_LOCK();
433 bcopy(smsg_bufc, new_logdata, MSG_BSIZE);
434 bzero(new_logdata+MSG_BSIZE, size - MSG_BSIZE);
435 /* this memory is now dead - clear it so that it compresses better
436 in case of suspend to disk etc. */
437 bzero(smsg_bufc, MSG_BSIZE);
438 msgbufp->msg_size = size;
439 msgbufp->msg_bufc = new_logdata;
440 LOG_UNLOCK();
441 printf("set system log size to %ld bytes\n", msgbufp->msg_size);
442}
443
444SYSCTL_LONG(_kern, OID_AUTO, msgbuf, CTLFLAG_RD, &temp_msgbuf.msg_size, "");
445
446/*
447 * This should be called by single user mode /sbin/dmesg only.
448 * It returns as much data still in the buffer as possible.
449 */
450int
b0d623f7
A
451log_dmesg(user_addr_t buffer, uint32_t buffersize, int32_t * retval) {
452 uint32_t i;
453 uint32_t localbuff_size = (msgbufp->msg_size + 2);
2d21ac55
A
454 int error = 0, newl, skip;
455 char *localbuff, *p, *copystart, ch;
b0d623f7 456 long copysize;
2d21ac55
A
457
458 if (!(localbuff = (char *)kalloc(localbuff_size))) {
459 printf("log_dmesg: unable to allocate memory\n");
460 return (ENOMEM);
461 }
462 /* in between here, the log could become bigger, but that's fine */
463 LOG_LOCK();
464
465 /*
466 * The message buffer is circular; start at the write pointer, and
467 * make one loop up to write pointer - 1.
468 */
469 p = msgbufp->msg_bufc + msgbufp->msg_bufx;
470 for (i = newl = skip = 0; p != msgbufp->msg_bufc + msgbufp->msg_bufx - 1; ++p) {
471 if (p >= msgbufp->msg_bufc + msgbufp->msg_size)
472 p = msgbufp->msg_bufc;
473 ch = *p;
474 /* Skip "\n<.*>" syslog sequences. */
475 if (skip) {
476 if (ch == '>')
477 newl = skip = 0;
478 continue;
479 }
480 if (newl && ch == '<') {
481 skip = 1;
482 continue;
483 }
484 if (ch == '\0')
485 continue;
486 newl = ch == '\n';
487 localbuff[i++] = ch;
593a1d5f
A
488 /* The original version of this routine contained a buffer
489 * overflow. At the time, a "small" targeted fix was desired
490 * so the change below to check the buffer bounds was made.
491 * TODO: rewrite this needlessly convoluted routine.
492 */
493 if (i == (localbuff_size - 2))
494 break;
2d21ac55
A
495 }
496 if (!newl)
497 localbuff[i++] = '\n';
498 localbuff[i++] = 0;
499
500 if (buffersize >= i) {
501 copystart = localbuff;
502 copysize = i;
503 } else {
504 copystart = localbuff + i - buffersize;
505 copysize = buffersize;
506 }
507
508 LOG_UNLOCK();
509
510 error = copyout(copystart, buffer, copysize);
511 if (!error)
512 *retval = copysize;
513
514 kfree(localbuff, localbuff_size);
515 return (error);
516}