subr_log.c revision 1.33
1/* $OpenBSD: subr_log.c,v 1.33 2015/11/24 23:59:22 deraadt Exp $ */ 2/* $NetBSD: subr_log.c,v 1.11 1996/03/30 22:24:44 christos Exp $ */ 3 4/* 5 * Copyright (c) 1982, 1986, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)subr_log.c 8.1 (Berkeley) 6/10/93 33 */ 34 35/* 36 * Error log buffer for kernel printf's. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/proc.h> 42#include <sys/vnode.h> 43#include <sys/ioctl.h> 44#include <sys/msgbuf.h> 45#include <sys/file.h> 46#include <sys/tty.h> 47#include <sys/signalvar.h> 48#include <sys/syslog.h> 49#include <sys/poll.h> 50#include <sys/malloc.h> 51#include <sys/filedesc.h> 52#include <sys/socket.h> 53#include <sys/socketvar.h> 54 55#ifdef KTRACE 56#include <sys/ktrace.h> 57#endif 58 59#include <sys/mount.h> 60#include <sys/syscallargs.h> 61 62#define LOG_RDPRI (PZERO + 1) 63 64#define LOG_ASYNC 0x04 65#define LOG_RDWAIT 0x08 66 67struct logsoftc { 68 int sc_state; /* see above for possibilities */ 69 struct selinfo sc_selp; /* process waiting on select call */ 70 int sc_pgid; /* process/group for async I/O */ 71 uid_t sc_siguid; /* uid for process that set sc_pgid */ 72 uid_t sc_sigeuid; /* euid for process that set sc_pgid */ 73} logsoftc; 74 75int log_open; /* also used in log() */ 76int msgbufmapped; /* is the message buffer mapped */ 77struct msgbuf *msgbufp; /* the mapped buffer, itself. */ 78struct msgbuf *consbufp; /* console message buffer. */ 79struct file *syslogf; 80 81void filt_logrdetach(struct knote *kn); 82int filt_logread(struct knote *kn, long hint); 83 84struct filterops logread_filtops = 85 { 1, NULL, filt_logrdetach, filt_logread}; 86 87int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg); 88 89void 90initmsgbuf(caddr_t buf, size_t bufsize) 91{ 92 struct msgbuf *mbp; 93 long new_bufs; 94 95 /* Sanity-check the given size. */ 96 if (bufsize < sizeof(struct msgbuf)) 97 return; 98 99 mbp = msgbufp = (struct msgbuf *)buf; 100 101 new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc); 102 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) || 103 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) || 104 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) { 105 /* 106 * If the buffer magic number is wrong, has changed 107 * size (which shouldn't happen often), or is 108 * internally inconsistent, initialize it. 109 */ 110 111 memset(buf, 0, bufsize); 112 mbp->msg_magic = MSG_MAGIC; 113 mbp->msg_bufs = new_bufs; 114 } 115 116 /* Always start new buffer data on a new line. */ 117 if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n') 118 msgbuf_putchar(msgbufp, '\n'); 119 120 /* mark it as ready for use. */ 121 msgbufmapped = 1; 122} 123 124void 125initconsbuf(void) 126{ 127 long new_bufs; 128 129 /* Set up a buffer to collect /dev/console output */ 130 consbufp = malloc(CONSBUFSIZE, M_TEMP, M_NOWAIT|M_ZERO); 131 if (consbufp) { 132 new_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc); 133 consbufp->msg_magic = MSG_MAGIC; 134 consbufp->msg_bufs = new_bufs; 135 } 136} 137 138void 139msgbuf_putchar(struct msgbuf *mbp, const char c) 140{ 141 if (mbp->msg_magic != MSG_MAGIC) 142 /* Nothing we can do */ 143 return; 144 145 mbp->msg_bufc[mbp->msg_bufx++] = c; 146 mbp->msg_bufl = min(mbp->msg_bufl+1, mbp->msg_bufs); 147 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs) 148 mbp->msg_bufx = 0; 149 /* If the buffer is full, keep the most recent data. */ 150 if (mbp->msg_bufr == mbp->msg_bufx) { 151 if (++mbp->msg_bufr >= mbp->msg_bufs) 152 mbp->msg_bufr = 0; 153 } 154} 155 156/*ARGSUSED*/ 157int 158logopen(dev_t dev, int flags, int mode, struct proc *p) 159{ 160 if (log_open) 161 return (EBUSY); 162 log_open = 1; 163 return (0); 164} 165 166/*ARGSUSED*/ 167int 168logclose(dev_t dev, int flag, int mode, struct proc *p) 169{ 170 171 if (syslogf) 172 FRELE(syslogf, p); 173 syslogf = NULL; 174 log_open = 0; 175 logsoftc.sc_state = 0; 176 return (0); 177} 178 179/*ARGSUSED*/ 180int 181logread(dev_t dev, struct uio *uio, int flag) 182{ 183 struct msgbuf *mbp = msgbufp; 184 long l; 185 int s; 186 int error = 0; 187 188 s = splhigh(); 189 while (mbp->msg_bufr == mbp->msg_bufx) { 190 if (flag & IO_NDELAY) { 191 splx(s); 192 return (EWOULDBLOCK); 193 } 194 logsoftc.sc_state |= LOG_RDWAIT; 195 error = tsleep(mbp, LOG_RDPRI | PCATCH, 196 "klog", 0); 197 if (error) { 198 splx(s); 199 return (error); 200 } 201 } 202 splx(s); 203 logsoftc.sc_state &= ~LOG_RDWAIT; 204 205 while (uio->uio_resid > 0) { 206 l = mbp->msg_bufx - mbp->msg_bufr; 207 if (l < 0) 208 l = mbp->msg_bufs - mbp->msg_bufr; 209 l = min(l, uio->uio_resid); 210 if (l == 0) 211 break; 212 error = uiomovei(&mbp->msg_bufc[mbp->msg_bufr], (int)l, uio); 213 if (error) 214 break; 215 mbp->msg_bufr += l; 216 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 217 mbp->msg_bufr = 0; 218 } 219 return (error); 220} 221 222/*ARGSUSED*/ 223int 224logpoll(dev_t dev, int events, struct proc *p) 225{ 226 int revents = 0; 227 int s = splhigh(); 228 229 if (events & (POLLIN | POLLRDNORM)) { 230 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 231 revents |= events & (POLLIN | POLLRDNORM); 232 else 233 selrecord(p, &logsoftc.sc_selp); 234 } 235 splx(s); 236 return (revents); 237} 238 239int 240logkqfilter(dev_t dev, struct knote *kn) 241{ 242 struct klist *klist; 243 int s; 244 245 switch (kn->kn_filter) { 246 case EVFILT_READ: 247 klist = &logsoftc.sc_selp.si_note; 248 kn->kn_fop = &logread_filtops; 249 break; 250 default: 251 return (EINVAL); 252 } 253 254 kn->kn_hook = (void *)msgbufp; 255 256 s = splhigh(); 257 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 258 splx(s); 259 260 return (0); 261} 262 263void 264filt_logrdetach(struct knote *kn) 265{ 266 int s = splhigh(); 267 268 SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext); 269 splx(s); 270} 271 272int 273filt_logread(struct knote *kn, long hint) 274{ 275 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 276 277 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 278 279 return (p->msg_bufx != p->msg_bufr); 280} 281 282void 283logwakeup(void) 284{ 285 if (!log_open) 286 return; 287 selwakeup(&logsoftc.sc_selp); 288 if (logsoftc.sc_state & LOG_ASYNC) 289 csignal(logsoftc.sc_pgid, SIGIO, 290 logsoftc.sc_siguid, logsoftc.sc_sigeuid); 291 if (logsoftc.sc_state & LOG_RDWAIT) { 292 wakeup(msgbufp); 293 logsoftc.sc_state &= ~LOG_RDWAIT; 294 } 295} 296 297/*ARGSUSED*/ 298int 299logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 300{ 301 struct file *fp; 302 long l; 303 int error, s; 304 305 switch (com) { 306 307 /* return number of characters immediately available */ 308 case FIONREAD: 309 s = splhigh(); 310 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 311 splx(s); 312 if (l < 0) 313 l += msgbufp->msg_bufs; 314 *(int *)data = l; 315 break; 316 317 case FIONBIO: 318 break; 319 320 case FIOASYNC: 321 if (*(int *)data) 322 logsoftc.sc_state |= LOG_ASYNC; 323 else 324 logsoftc.sc_state &= ~LOG_ASYNC; 325 break; 326 327 case TIOCSPGRP: 328 logsoftc.sc_pgid = *(int *)data; 329 logsoftc.sc_siguid = p->p_ucred->cr_ruid; 330 logsoftc.sc_sigeuid = p->p_ucred->cr_uid; 331 break; 332 333 case TIOCGPGRP: 334 *(int *)data = logsoftc.sc_pgid; 335 break; 336 337 case LIOCSFD: 338 if ((error = suser(p, 0)) != 0) 339 return (error); 340 if ((error = getsock(p, *(int *)data, &fp)) != 0) 341 return (error); 342 if (syslogf) 343 FRELE(syslogf, p); 344 syslogf = fp; 345 break; 346 347 default: 348 return (ENOTTY); 349 } 350 return (0); 351} 352 353int 354sys_sendsyslog(struct proc *p, void *v, register_t *retval) 355{ 356 struct sys_sendsyslog_args /* { 357 syscallarg(const void *) buf; 358 syscallarg(size_t) nbyte; 359 } */ *uap = v; 360 struct sys_sendsyslog2_args oap; 361 362 SCARG(&oap, buf) = SCARG(uap, buf); 363 SCARG(&oap, nbyte) = SCARG(uap, nbyte); 364 SCARG(&oap, flags) = 0; 365 return sys_sendsyslog2(p, &oap, retval); 366} 367 368int 369sys_sendsyslog2(struct proc *p, void *v, register_t *retval) 370{ 371 struct sys_sendsyslog2_args /* { 372 syscallarg(const void *) buf; 373 syscallarg(size_t) nbyte; 374 syscallarg(int) flags; 375 } */ *uap = v; 376 int error; 377#ifndef SMALL_KERNEL 378 static int dropped_count, orig_error; 379 int len; 380 char buf[64]; 381 382 if (dropped_count) { 383 len = snprintf(buf, sizeof(buf), 384 "<%d>sendsyslog: dropped %d message%s, error %d", 385 LOG_KERN|LOG_WARNING, dropped_count, 386 dropped_count == 1 ? "" : "s", orig_error); 387 error = dosendsyslog(p, buf, MIN((size_t)len, sizeof(buf) - 1), 388 SCARG(uap, flags), UIO_SYSSPACE); 389 if (error) { 390 dropped_count++; 391 return (error); 392 } 393 dropped_count = 0; 394 } 395#endif 396 error = dosendsyslog(p, SCARG(uap, buf), SCARG(uap, nbyte), 397 SCARG(uap, flags), UIO_USERSPACE); 398#ifndef SMALL_KERNEL 399 if (error && error != ENOTCONN) { 400 dropped_count++; 401 orig_error = error; 402 } 403#endif 404 return (error); 405} 406 407int 408dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags, 409 enum uio_seg sflg) 410{ 411#ifdef KTRACE 412 struct iovec *ktriov = NULL; 413 int iovlen; 414#endif 415 extern struct tty *constty; 416 struct iovec aiov; 417 struct uio auio; 418 struct file *f; 419 size_t len; 420 int error; 421 422 if (syslogf == NULL) { 423 if (constty && (flags & LOG_CONS)) { 424 int i; 425 426 /* Skip syslog prefix */ 427 if (nbyte >= 4 && buf[0] == '<' && 428 buf[3] == '>') { 429 buf += 4; 430 nbyte -= 4; 431 } 432 for (i = 0; i < nbyte; i++) 433 tputchar(buf[i], constty); 434 tputchar('\n', constty); 435 } 436 return (ENOTCONN); 437 } 438 f = syslogf; 439 FREF(f); 440 441 aiov.iov_base = (char *)buf; 442 aiov.iov_len = nbyte; 443 auio.uio_iov = &aiov; 444 auio.uio_iovcnt = 1; 445 auio.uio_segflg = sflg; 446 auio.uio_rw = UIO_WRITE; 447 auio.uio_procp = p; 448 auio.uio_offset = 0; 449 auio.uio_resid = aiov.iov_len; 450#ifdef KTRACE 451 if (KTRPOINT(p, KTR_GENIO)) { 452 ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec), 453 M_TEMP, M_WAITOK); 454 iovlen = auio.uio_iovcnt * sizeof (struct iovec); 455 456 memcpy(ktriov, auio.uio_iov, iovlen); 457 } 458#endif 459 460 len = auio.uio_resid; 461 error = sosend(f->f_data, NULL, &auio, NULL, NULL, 0); 462 if (error == 0) 463 len -= auio.uio_resid; 464 465#ifdef KTRACE 466 if (ktriov != NULL) { 467 if (error == 0) 468 ktrgenio(p, -1, UIO_WRITE, ktriov, len); 469 free(ktriov, M_TEMP, iovlen); 470 } 471#endif 472 FRELE(f, p); 473 return error; 474} 475