subr_log.c revision 1.34
1/* $OpenBSD: subr_log.c,v 1.34 2015/12/05 10:11:53 tedu 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 156int 157logopen(dev_t dev, int flags, int mode, struct proc *p) 158{ 159 if (log_open) 160 return (EBUSY); 161 log_open = 1; 162 return (0); 163} 164 165int 166logclose(dev_t dev, int flag, int mode, struct proc *p) 167{ 168 169 if (syslogf) 170 FRELE(syslogf, p); 171 syslogf = NULL; 172 log_open = 0; 173 logsoftc.sc_state = 0; 174 return (0); 175} 176 177int 178logread(dev_t dev, struct uio *uio, int flag) 179{ 180 struct msgbuf *mbp = msgbufp; 181 long l; 182 int s; 183 int error = 0; 184 185 s = splhigh(); 186 while (mbp->msg_bufr == mbp->msg_bufx) { 187 if (flag & IO_NDELAY) { 188 splx(s); 189 return (EWOULDBLOCK); 190 } 191 logsoftc.sc_state |= LOG_RDWAIT; 192 error = tsleep(mbp, LOG_RDPRI | PCATCH, 193 "klog", 0); 194 if (error) { 195 splx(s); 196 return (error); 197 } 198 } 199 splx(s); 200 logsoftc.sc_state &= ~LOG_RDWAIT; 201 202 while (uio->uio_resid > 0) { 203 l = mbp->msg_bufx - mbp->msg_bufr; 204 if (l < 0) 205 l = mbp->msg_bufs - mbp->msg_bufr; 206 l = min(l, uio->uio_resid); 207 if (l == 0) 208 break; 209 error = uiomovei(&mbp->msg_bufc[mbp->msg_bufr], (int)l, uio); 210 if (error) 211 break; 212 mbp->msg_bufr += l; 213 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 214 mbp->msg_bufr = 0; 215 } 216 return (error); 217} 218 219int 220logpoll(dev_t dev, int events, struct proc *p) 221{ 222 int revents = 0; 223 int s = splhigh(); 224 225 if (events & (POLLIN | POLLRDNORM)) { 226 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 227 revents |= events & (POLLIN | POLLRDNORM); 228 else 229 selrecord(p, &logsoftc.sc_selp); 230 } 231 splx(s); 232 return (revents); 233} 234 235int 236logkqfilter(dev_t dev, struct knote *kn) 237{ 238 struct klist *klist; 239 int s; 240 241 switch (kn->kn_filter) { 242 case EVFILT_READ: 243 klist = &logsoftc.sc_selp.si_note; 244 kn->kn_fop = &logread_filtops; 245 break; 246 default: 247 return (EINVAL); 248 } 249 250 kn->kn_hook = (void *)msgbufp; 251 252 s = splhigh(); 253 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 254 splx(s); 255 256 return (0); 257} 258 259void 260filt_logrdetach(struct knote *kn) 261{ 262 int s = splhigh(); 263 264 SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext); 265 splx(s); 266} 267 268int 269filt_logread(struct knote *kn, long hint) 270{ 271 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 272 273 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 274 275 return (p->msg_bufx != p->msg_bufr); 276} 277 278void 279logwakeup(void) 280{ 281 if (!log_open) 282 return; 283 selwakeup(&logsoftc.sc_selp); 284 if (logsoftc.sc_state & LOG_ASYNC) 285 csignal(logsoftc.sc_pgid, SIGIO, 286 logsoftc.sc_siguid, logsoftc.sc_sigeuid); 287 if (logsoftc.sc_state & LOG_RDWAIT) { 288 wakeup(msgbufp); 289 logsoftc.sc_state &= ~LOG_RDWAIT; 290 } 291} 292 293int 294logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 295{ 296 struct file *fp; 297 long l; 298 int error, s; 299 300 switch (com) { 301 302 /* return number of characters immediately available */ 303 case FIONREAD: 304 s = splhigh(); 305 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 306 splx(s); 307 if (l < 0) 308 l += msgbufp->msg_bufs; 309 *(int *)data = l; 310 break; 311 312 case FIONBIO: 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 logsoftc.sc_siguid = p->p_ucred->cr_ruid; 325 logsoftc.sc_sigeuid = p->p_ucred->cr_uid; 326 break; 327 328 case TIOCGPGRP: 329 *(int *)data = logsoftc.sc_pgid; 330 break; 331 332 case LIOCSFD: 333 if ((error = suser(p, 0)) != 0) 334 return (error); 335 if ((error = getsock(p, *(int *)data, &fp)) != 0) 336 return (error); 337 if (syslogf) 338 FRELE(syslogf, p); 339 syslogf = fp; 340 break; 341 342 default: 343 return (ENOTTY); 344 } 345 return (0); 346} 347 348int 349sys_sendsyslog(struct proc *p, void *v, register_t *retval) 350{ 351 struct sys_sendsyslog_args /* { 352 syscallarg(const void *) buf; 353 syscallarg(size_t) nbyte; 354 } */ *uap = v; 355 struct sys_sendsyslog2_args oap; 356 357 SCARG(&oap, buf) = SCARG(uap, buf); 358 SCARG(&oap, nbyte) = SCARG(uap, nbyte); 359 SCARG(&oap, flags) = 0; 360 return sys_sendsyslog2(p, &oap, retval); 361} 362 363int 364sys_sendsyslog2(struct proc *p, void *v, register_t *retval) 365{ 366 struct sys_sendsyslog2_args /* { 367 syscallarg(const void *) buf; 368 syscallarg(size_t) nbyte; 369 syscallarg(int) flags; 370 } */ *uap = v; 371 int error; 372#ifndef SMALL_KERNEL 373 static int dropped_count, orig_error; 374 int len; 375 char buf[64]; 376 377 if (dropped_count) { 378 len = snprintf(buf, sizeof(buf), 379 "<%d>sendsyslog: dropped %d message%s, error %d", 380 LOG_KERN|LOG_WARNING, dropped_count, 381 dropped_count == 1 ? "" : "s", orig_error); 382 error = dosendsyslog(p, buf, MIN((size_t)len, sizeof(buf) - 1), 383 SCARG(uap, flags), UIO_SYSSPACE); 384 if (error) { 385 dropped_count++; 386 return (error); 387 } 388 dropped_count = 0; 389 } 390#endif 391 error = dosendsyslog(p, SCARG(uap, buf), SCARG(uap, nbyte), 392 SCARG(uap, flags), UIO_USERSPACE); 393#ifndef SMALL_KERNEL 394 if (error && error != ENOTCONN) { 395 dropped_count++; 396 orig_error = error; 397 } 398#endif 399 return (error); 400} 401 402int 403dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags, 404 enum uio_seg sflg) 405{ 406#ifdef KTRACE 407 struct iovec *ktriov = NULL; 408 int iovlen; 409#endif 410 extern struct tty *constty; 411 struct iovec aiov; 412 struct uio auio; 413 struct file *f; 414 size_t len; 415 int error; 416 417 if (syslogf == NULL) { 418 if (constty && (flags & LOG_CONS)) { 419 int i; 420 421 /* Skip syslog prefix */ 422 if (nbyte >= 4 && buf[0] == '<' && 423 buf[3] == '>') { 424 buf += 4; 425 nbyte -= 4; 426 } 427 for (i = 0; i < nbyte; i++) 428 tputchar(buf[i], constty); 429 tputchar('\n', constty); 430 } 431 return (ENOTCONN); 432 } 433 f = syslogf; 434 FREF(f); 435 436 aiov.iov_base = (char *)buf; 437 aiov.iov_len = nbyte; 438 auio.uio_iov = &aiov; 439 auio.uio_iovcnt = 1; 440 auio.uio_segflg = sflg; 441 auio.uio_rw = UIO_WRITE; 442 auio.uio_procp = p; 443 auio.uio_offset = 0; 444 auio.uio_resid = aiov.iov_len; 445#ifdef KTRACE 446 if (KTRPOINT(p, KTR_GENIO)) { 447 ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec), 448 M_TEMP, M_WAITOK); 449 iovlen = auio.uio_iovcnt * sizeof (struct iovec); 450 451 memcpy(ktriov, auio.uio_iov, iovlen); 452 } 453#endif 454 455 len = auio.uio_resid; 456 error = sosend(f->f_data, NULL, &auio, NULL, NULL, 0); 457 if (error == 0) 458 len -= auio.uio_resid; 459 460#ifdef KTRACE 461 if (ktriov != NULL) { 462 if (error == 0) 463 ktrgenio(p, -1, UIO_WRITE, ktriov, len); 464 free(ktriov, M_TEMP, iovlen); 465 } 466#endif 467 FRELE(f, p); 468 return error; 469} 470