1/* 2 * Copyright (c) 2000-2010 Apple, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 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> 70#include <sys/proc_internal.h> 71#include <sys/vnode.h> 72#include <sys/ioctl.h> 73#include <sys/msgbuf.h> 74#include <sys/file_internal.h> 75#include <sys/errno.h> 76#include <sys/select.h> 77#include <sys/kernel.h> 78#include <kern/thread.h> 79#include <sys/lock.h> 80#include <sys/signalvar.h> 81#include <sys/conf.h> 82#include <sys/sysctl.h> 83#include <kern/kalloc.h> 84#include <pexpert/pexpert.h> 85 86/* XXX should be in a common header somewhere */ 87extern void klogwakeup(void); 88extern void logwakeup(void); 89 90#define LOG_RDPRI (PZERO + 1) 91 92#define LOG_NBIO 0x02 93#define LOG_ASYNC 0x04 94#define LOG_RDWAIT 0x08 95 96/* All globals should be accessed under LOG_LOCK() */ 97 98/* logsoftc only valid while log_open=1 */ 99struct logsoftc { 100 int sc_state; /* see above for possibilities */ 101 struct selinfo sc_selp; /* thread waiting for select */ 102 int sc_pgid; /* process/group for async I/O */ 103} logsoftc; 104 105int log_open; /* also used in log() */ 106char smsg_bufc[CONFIG_MSG_BSIZE]; /* static buffer */ 107struct msgbuf msgbuf = {MSG_MAGIC,sizeof(smsg_bufc),0,0,smsg_bufc}; 108struct msgbuf *msgbufp = &msgbuf; 109static int logentrypend = 0; 110 111/* the following are implemented in osfmk/kern/printf.c */ 112extern void bsd_log_lock(void); 113extern void bsd_log_unlock(void); 114extern void bsd_log_init(void); 115 116/* XXX wants a linker set so these can be static */ 117extern d_open_t logopen; 118extern d_close_t logclose; 119extern d_read_t logread; 120extern d_ioctl_t logioctl; 121extern d_select_t logselect; 122 123/* 124 * Serialize log access. Note that the log can be written at interrupt level, 125 * so any log manipulations that can be done from, or affect, another processor 126 * at interrupt level must be guarded with a spin lock. 127 */ 128 129#define LOG_LOCK() bsd_log_lock() 130#define LOG_UNLOCK() bsd_log_unlock() 131 132#if DEBUG 133#define LOG_SETSIZE_DEBUG(x...) kprintf(x) 134#else 135#define LOG_SETSIZE_DEBUG(x...) do { } while(0) 136#endif 137 138static int sysctl_kern_msgbuf(struct sysctl_oid *oidp, 139 void *arg1, 140 int arg2, 141 struct sysctl_req *req); 142 143/*ARGSUSED*/ 144int 145logopen(__unused dev_t dev, __unused int flags, __unused int mode, struct proc *p) 146{ 147 LOG_LOCK(); 148 if (log_open) { 149 LOG_UNLOCK(); 150 return (EBUSY); 151 } 152 logsoftc.sc_pgid = p->p_pid; /* signal process only */ 153 log_open = 1; 154 155 LOG_UNLOCK(); 156 157 return (0); 158} 159 160/*ARGSUSED*/ 161int 162logclose(__unused dev_t dev, __unused int flag, __unused int devtype, __unused struct proc *p) 163{ 164 LOG_LOCK(); 165 selwakeup(&logsoftc.sc_selp); 166 selthreadclear(&logsoftc.sc_selp); 167 log_open = 0; 168 LOG_UNLOCK(); 169 return (0); 170} 171 172/*ARGSUSED*/ 173int 174logread(__unused dev_t dev, struct uio *uio, int flag) 175{ 176 int l; 177 int error = 0; 178 179 LOG_LOCK(); 180 while (msgbufp->msg_bufr == msgbufp->msg_bufx) { 181 if (flag & IO_NDELAY) { 182 error = EWOULDBLOCK; 183 goto out; 184 } 185 if (logsoftc.sc_state & LOG_NBIO) { 186 error = EWOULDBLOCK; 187 goto out; 188 } 189 logsoftc.sc_state |= LOG_RDWAIT; 190 LOG_UNLOCK(); 191 /* 192 * If the wakeup is missed the ligtening bolt will wake this up 193 * if there are any new characters. If that doesn't do it 194 * then wait for 5 sec and reevaluate 195 */ 196 if ((error = tsleep((caddr_t)msgbufp, LOG_RDPRI | PCATCH, 197 "klog", 5 * hz)) != 0) { 198 /* if it times out; ignore */ 199 if (error != EWOULDBLOCK) 200 return (error); 201 } 202 LOG_LOCK(); 203 } 204 logsoftc.sc_state &= ~LOG_RDWAIT; 205 206 while (uio_resid(uio) > 0) { 207 int readpos; 208 209 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 210 if (l < 0) 211 l = msgbufp->msg_size - msgbufp->msg_bufr; 212 l = min(l, uio_resid(uio)); 213 if (l == 0) 214 break; 215 216 readpos = msgbufp->msg_bufr; 217 LOG_UNLOCK(); 218 error = uiomove((caddr_t)&msgbufp->msg_bufc[readpos], 219 l, uio); 220 LOG_LOCK(); 221 if (error) 222 break; 223 msgbufp->msg_bufr = readpos + l; 224 if (msgbufp->msg_bufr >= msgbufp->msg_size) 225 msgbufp->msg_bufr = 0; 226 } 227out: 228 LOG_UNLOCK(); 229 return (error); 230} 231 232/*ARGSUSED*/ 233int 234logselect(__unused dev_t dev, int rw, void * wql, struct proc *p) 235{ 236 switch (rw) { 237 238 case FREAD: 239 LOG_LOCK(); 240 if (msgbufp->msg_bufr != msgbufp->msg_bufx) { 241 LOG_UNLOCK(); 242 return (1); 243 } 244 selrecord(p, &logsoftc.sc_selp, wql); 245 LOG_UNLOCK(); 246 break; 247 } 248 return (0); 249} 250 251void 252logwakeup(void) 253{ 254 int pgid; 255 256 LOG_LOCK(); 257 if (!log_open) { 258 LOG_UNLOCK(); 259 return; 260 } 261 selwakeup(&logsoftc.sc_selp); 262 if (logsoftc.sc_state & LOG_ASYNC) { 263 pgid = logsoftc.sc_pgid; 264 LOG_UNLOCK(); 265 if (pgid < 0) 266 gsignal(-pgid, SIGIO); 267 else 268 proc_signal(pgid, SIGIO); 269 LOG_LOCK(); 270 } 271 if (logsoftc.sc_state & LOG_RDWAIT) { 272 wakeup((caddr_t)msgbufp); 273 logsoftc.sc_state &= ~LOG_RDWAIT; 274 } 275 LOG_UNLOCK(); 276} 277 278void 279klogwakeup(void) 280{ 281 LOG_LOCK(); 282 if (logentrypend && log_open) { 283 logentrypend = 0; /* only reset if someone will be reading */ 284 LOG_UNLOCK(); 285 logwakeup(); 286 } else { 287 LOG_UNLOCK(); 288 } 289} 290 291/*ARGSUSED*/ 292int 293logioctl(__unused dev_t dev, u_long com, caddr_t data, __unused int flag, __unused struct proc *p) 294{ 295 int l; 296 297 LOG_LOCK(); 298 switch (com) { 299 300 /* return number of characters immediately available */ 301 case FIONREAD: 302 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 303 if (l < 0) 304 l += msgbufp->msg_size; 305 *(off_t *)data = l; 306 break; 307 308 case FIONBIO: 309 if (*(int *)data) 310 logsoftc.sc_state |= LOG_NBIO; 311 else 312 logsoftc.sc_state &= ~LOG_NBIO; 313 break; 314 315 case FIOASYNC: 316 if (*(int *)data) 317 logsoftc.sc_state |= LOG_ASYNC; 318 else 319 logsoftc.sc_state &= ~LOG_ASYNC; 320 break; 321 322 case TIOCSPGRP: 323 logsoftc.sc_pgid = *(int *)data; 324 break; 325 326 case TIOCGPGRP: 327 *(int *)data = logsoftc.sc_pgid; 328 break; 329 330 default: 331 LOG_UNLOCK(); 332 return (-1); 333 } 334 LOG_UNLOCK(); 335 return (0); 336} 337 338void 339bsd_log_init(void) 340{ 341 /* After this point, we must be ready to accept characters */ 342} 343 344 345/* 346 * log_putc_locked 347 * 348 * Decription: Output a character to the log; assumes the LOG_LOCK() is held 349 * by the caller. 350 * 351 * Parameters: c Character to output 352 * 353 * Returns: (void) 354 * 355 * Notes: This functions is used for multibyte output to the log; it 356 * should be used preferrentially where possible to ensure that 357 * log entries do not end up interspersed due to preemption or 358 * SMP reentrancy. 359 */ 360void 361log_putc_locked(char c) 362{ 363 struct msgbuf *mbp; 364 365 mbp = msgbufp; 366 mbp->msg_bufc[mbp->msg_bufx++] = c; 367 logentrypend = 1; 368 if (mbp->msg_bufx >= msgbufp->msg_size) 369 mbp->msg_bufx = 0; 370} 371 372 373/* 374 * log_putc 375 * 376 * Decription: Output a character to the log; assumes the LOG_LOCK() is NOT 377 * held by the caller. 378 * 379 * Parameters: c Character to output 380 * 381 * Returns: (void) 382 * 383 * Notes: This function is used for syingle byte output to the log. It 384 * primarily exists to maintain binary backward compatibility. 385 */ 386void 387log_putc(char c) 388{ 389 LOG_LOCK(); 390 log_putc_locked(c); 391 LOG_UNLOCK(); 392} 393 394 395/* 396 * it is possible to increase the kernel log buffer size by adding 397 * msgbuf=n 398 * to the kernel command line, and to read the current size using 399 * sysctl kern.msgbuf 400 * If there is no parameter on the kernel command line, the buffer is 401 * allocated statically and is CONFIG_MSG_BSIZE characters in size, otherwise 402 * memory is dynamically allocated. Memory management must already be up. 403 */ 404int 405log_setsize(int size) { 406 char *new_logdata; 407 int new_logsize, new_bufr, new_bufx; 408 char *old_logdata; 409 int old_logsize, old_bufr, old_bufx; 410 int i, count; 411 char *p, ch; 412 413 if (size > MAX_MSG_BSIZE) 414 return (EINVAL); 415 416 if (size <= 0) 417 return (EINVAL); 418 419 new_logsize = size; 420 if (!(new_logdata = (char*)kalloc(size))) { 421 printf("log_setsize: unable to allocate memory\n"); 422 return (ENOMEM); 423 } 424 bzero(new_logdata, new_logsize); 425 426 LOG_LOCK(); 427 428 old_logsize = msgbufp->msg_size; 429 old_logdata = msgbufp->msg_bufc; 430 old_bufr = msgbufp->msg_bufr; 431 old_bufx = msgbufp->msg_bufx; 432 433 LOG_SETSIZE_DEBUG("log_setsize(%d): old_logdata %p old_logsize %d old_bufr %d old_bufx %d\n", 434 size, old_logdata, old_logsize, old_bufr, old_bufx); 435 436 /* start "new_logsize" bytes before the write pointer */ 437 if (new_logsize <= old_bufx) { 438 count = new_logsize; 439 p = old_logdata + old_bufx - count; 440 } else { 441 /* 442 * if new buffer is bigger, copy what we have and let the 443 * bzero above handle the difference 444 */ 445 count = MIN(new_logsize, old_logsize); 446 p = old_logdata + old_logsize - (count - old_bufx); 447 } 448 for (i = 0; i < count; i++) { 449 if (p >= old_logdata + old_logsize) 450 p = old_logdata; 451 452 ch = *p++; 453 new_logdata[i] = ch; 454 } 455 456 new_bufx = i; 457 if (new_bufx >= new_logsize) 458 new_bufx = 0; 459 msgbufp->msg_bufx = new_bufx; 460 461 new_bufr = old_bufx - old_bufr; /* how much were we trailing bufx by? */ 462 if (new_bufr < 0) 463 new_bufr += old_logsize; 464 new_bufr = new_bufx - new_bufr; /* now relative to oldest data in new buffer */ 465 if (new_bufr < 0) 466 new_bufr += new_logsize; 467 msgbufp->msg_bufr = new_bufr; 468 469 msgbufp->msg_size = new_logsize; 470 msgbufp->msg_bufc = new_logdata; 471 472 LOG_SETSIZE_DEBUG("log_setsize(%d): new_logdata %p new_logsize %d new_bufr %d new_bufx %d\n", 473 size, new_logdata, new_logsize, new_bufr, new_bufx); 474 475 LOG_UNLOCK(); 476 477 /* this memory is now dead - clear it so that it compresses better 478 in case of suspend to disk etc. */ 479 bzero(old_logdata, old_logsize); 480 if (old_logdata != smsg_bufc) { 481 /* dynamic memory that must be freed */ 482 kfree(old_logdata, old_logsize); 483 } 484 485 printf("set system log size to %d bytes\n", new_logsize); 486 487 return 0; 488} 489 490SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, 0, 0, sysctl_kern_msgbuf, "I", ""); 491 492static int sysctl_kern_msgbuf(struct sysctl_oid *oidp __unused, 493 void *arg1 __unused, 494 int arg2 __unused, 495 struct sysctl_req *req) 496{ 497 int old_bufsize, bufsize; 498 int error; 499 500 LOG_LOCK(); 501 old_bufsize = bufsize = msgbufp->msg_size; 502 LOG_UNLOCK(); 503 504 error = sysctl_io_number(req, bufsize, sizeof(bufsize), &bufsize, NULL); 505 if (error) 506 return (error); 507 508 if (bufsize != old_bufsize) { 509 error = log_setsize(bufsize); 510 } 511 512 return (error); 513} 514 515 516/* 517 * This should be called by /sbin/dmesg only via libproc. 518 * It returns as much data still in the buffer as possible. 519 */ 520int 521log_dmesg(user_addr_t buffer, uint32_t buffersize, int32_t * retval) { 522 uint32_t i; 523 uint32_t localbuff_size; 524 int error = 0, newl, skip; 525 char *localbuff, *p, *copystart, ch; 526 size_t copysize; 527 528 LOG_LOCK(); 529 localbuff_size = (msgbufp->msg_size + 2); /* + '\n' + '\0' */ 530 LOG_UNLOCK(); 531 532 /* Allocate a temporary non-circular buffer for copyout */ 533 if (!(localbuff = (char *)kalloc(localbuff_size))) { 534 printf("log_dmesg: unable to allocate memory\n"); 535 return (ENOMEM); 536 } 537 538 /* in between here, the log could become bigger, but that's fine */ 539 LOG_LOCK(); 540 541 /* 542 * The message buffer is circular; start at the write pointer, and 543 * make one loop up to write pointer - 1. 544 */ 545 p = msgbufp->msg_bufc + msgbufp->msg_bufx; 546 for (i = newl = skip = 0; p != msgbufp->msg_bufc + msgbufp->msg_bufx - 1; ++p) { 547 if (p >= msgbufp->msg_bufc + msgbufp->msg_size) 548 p = msgbufp->msg_bufc; 549 ch = *p; 550 /* Skip "\n<.*>" syslog sequences. */ 551 if (skip) { 552 if (ch == '>') 553 newl = skip = 0; 554 continue; 555 } 556 if (newl && ch == '<') { 557 skip = 1; 558 continue; 559 } 560 if (ch == '\0') 561 continue; 562 newl = (ch == '\n'); 563 localbuff[i++] = ch; 564 /* The original version of this routine contained a buffer 565 * overflow. At the time, a "small" targeted fix was desired 566 * so the change below to check the buffer bounds was made. 567 * TODO: rewrite this needlessly convoluted routine. 568 */ 569 if (i == (localbuff_size - 2)) 570 break; 571 } 572 if (!newl) 573 localbuff[i++] = '\n'; 574 localbuff[i++] = 0; 575 576 if (buffersize >= i) { 577 copystart = localbuff; 578 copysize = i; 579 } else { 580 copystart = localbuff + i - buffersize; 581 copysize = buffersize; 582 } 583 584 LOG_UNLOCK(); 585 586 error = copyout(copystart, buffer, copysize); 587 if (!error) 588 *retval = copysize; 589 590 kfree(localbuff, localbuff_size); 591 return (error); 592} 593