subr_log.c revision 1.60
1/* $OpenBSD: subr_log.c,v 1.60 2019/12/24 12:56:07 bluhm 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#include <sys/fcntl.h> 55#include <sys/timeout.h> 56 57#ifdef KTRACE 58#include <sys/ktrace.h> 59#endif 60 61#include <sys/mount.h> 62#include <sys/syscallargs.h> 63 64#include <dev/cons.h> 65 66#define LOG_RDPRI (PZERO + 1) 67#define LOG_TICK 50 /* log tick interval in msec */ 68 69#define LOG_ASYNC 0x04 70#define LOG_RDWAIT 0x08 71 72struct logsoftc { 73 int sc_state; /* see above for possibilities */ 74 struct selinfo sc_selp; /* process waiting on select call */ 75 int sc_pgid; /* process/group for async I/O */ 76 uid_t sc_siguid; /* uid for process that set sc_pgid */ 77 uid_t sc_sigeuid; /* euid for process that set sc_pgid */ 78 int sc_need_wakeup; /* if set, wake up waiters */ 79 struct timeout sc_tick; /* wakeup poll timeout */ 80} logsoftc; 81 82int log_open; /* also used in log() */ 83int msgbufmapped; /* is the message buffer mapped */ 84struct msgbuf *msgbufp; /* the mapped buffer, itself. */ 85struct msgbuf *consbufp; /* console message buffer. */ 86struct file *syslogf; 87 88void filt_logrdetach(struct knote *kn); 89int filt_logread(struct knote *kn, long hint); 90 91struct filterops logread_filtops = 92 { 1, NULL, filt_logrdetach, filt_logread}; 93 94int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg); 95void logtick(void *); 96 97void 98initmsgbuf(caddr_t buf, size_t bufsize) 99{ 100 struct msgbuf *mbp; 101 long new_bufs; 102 103 /* Sanity-check the given size. */ 104 if (bufsize < sizeof(struct msgbuf)) 105 return; 106 107 mbp = msgbufp = (struct msgbuf *)buf; 108 109 new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc); 110 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) || 111 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) || 112 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) { 113 /* 114 * If the buffer magic number is wrong, has changed 115 * size (which shouldn't happen often), or is 116 * internally inconsistent, initialize it. 117 */ 118 119 memset(buf, 0, bufsize); 120 mbp->msg_magic = MSG_MAGIC; 121 mbp->msg_bufs = new_bufs; 122 } 123 124 /* Always start new buffer data on a new line. */ 125 if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n') 126 msgbuf_putchar(msgbufp, '\n'); 127 128 /* mark it as ready for use. */ 129 msgbufmapped = 1; 130} 131 132void 133initconsbuf(void) 134{ 135 /* Set up a buffer to collect /dev/console output */ 136 consbufp = malloc(CONSBUFSIZE, M_TTYS, M_WAITOK | M_ZERO); 137 consbufp->msg_magic = MSG_MAGIC; 138 consbufp->msg_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc); 139} 140 141void 142msgbuf_putchar(struct msgbuf *mbp, const char c) 143{ 144 int s; 145 146 if (mbp->msg_magic != MSG_MAGIC) 147 /* Nothing we can do */ 148 return; 149 150 s = splhigh(); 151 mbp->msg_bufc[mbp->msg_bufx++] = c; 152 mbp->msg_bufl = lmin(mbp->msg_bufl+1, mbp->msg_bufs); 153 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs) 154 mbp->msg_bufx = 0; 155 /* If the buffer is full, keep the most recent data. */ 156 if (mbp->msg_bufr == mbp->msg_bufx) { 157 if (++mbp->msg_bufr >= mbp->msg_bufs) 158 mbp->msg_bufr = 0; 159 mbp->msg_bufd++; 160 } 161 splx(s); 162} 163 164int 165logopen(dev_t dev, int flags, int mode, struct proc *p) 166{ 167 if (log_open) 168 return (EBUSY); 169 log_open = 1; 170 timeout_set(&logsoftc.sc_tick, logtick, NULL); 171 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 172 return (0); 173} 174 175int 176logclose(dev_t dev, int flag, int mode, struct proc *p) 177{ 178 struct file *fp; 179 180 fp = syslogf; 181 syslogf = NULL; 182 if (fp) 183 FRELE(fp, p); 184 log_open = 0; 185 timeout_del(&logsoftc.sc_tick); 186 logsoftc.sc_state = 0; 187 return (0); 188} 189 190int 191logread(dev_t dev, struct uio *uio, int flag) 192{ 193 struct msgbuf *mbp = msgbufp; 194 size_t l; 195 int s, error = 0; 196 197 s = splhigh(); 198 while (mbp->msg_bufr == mbp->msg_bufx) { 199 if (flag & IO_NDELAY) { 200 error = EWOULDBLOCK; 201 goto out; 202 } 203 logsoftc.sc_state |= LOG_RDWAIT; 204 error = tsleep(mbp, LOG_RDPRI | PCATCH, 205 "klog", 0); 206 if (error) 207 goto out; 208 } 209 logsoftc.sc_state &= ~LOG_RDWAIT; 210 211 if (mbp->msg_bufd > 0) { 212 char buf[64]; 213 214 l = snprintf(buf, sizeof(buf), 215 "<%d>klog: dropped %ld byte%s, message buffer full\n", 216 LOG_KERN|LOG_WARNING, mbp->msg_bufd, 217 mbp->msg_bufd == 1 ? "" : "s"); 218 error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio); 219 if (error) 220 goto out; 221 mbp->msg_bufd = 0; 222 } 223 224 while (uio->uio_resid > 0) { 225 if (mbp->msg_bufx >= mbp->msg_bufr) 226 l = mbp->msg_bufx - mbp->msg_bufr; 227 else 228 l = mbp->msg_bufs - mbp->msg_bufr; 229 l = ulmin(l, uio->uio_resid); 230 if (l == 0) 231 break; 232 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], l, uio); 233 if (error) 234 break; 235 mbp->msg_bufr += l; 236 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 237 mbp->msg_bufr = 0; 238 } 239 out: 240 splx(s); 241 return (error); 242} 243 244int 245logpoll(dev_t dev, int events, struct proc *p) 246{ 247 int s, revents = 0; 248 249 s = splhigh(); 250 if (events & (POLLIN | POLLRDNORM)) { 251 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 252 revents |= events & (POLLIN | POLLRDNORM); 253 else 254 selrecord(p, &logsoftc.sc_selp); 255 } 256 splx(s); 257 return (revents); 258} 259 260int 261logkqfilter(dev_t dev, struct knote *kn) 262{ 263 struct klist *klist; 264 int s; 265 266 switch (kn->kn_filter) { 267 case EVFILT_READ: 268 klist = &logsoftc.sc_selp.si_note; 269 kn->kn_fop = &logread_filtops; 270 break; 271 default: 272 return (EINVAL); 273 } 274 275 kn->kn_hook = (void *)msgbufp; 276 277 s = splhigh(); 278 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 279 splx(s); 280 281 return (0); 282} 283 284void 285filt_logrdetach(struct knote *kn) 286{ 287 int s; 288 289 s = splhigh(); 290 SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext); 291 splx(s); 292} 293 294int 295filt_logread(struct knote *kn, long hint) 296{ 297 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 298 int s, event = 0; 299 300 s = splhigh(); 301 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 302 event = (p->msg_bufx != p->msg_bufr); 303 splx(s); 304 return (event); 305} 306 307void 308logwakeup(void) 309{ 310 /* 311 * The actual wakeup has to be deferred because logwakeup() can be 312 * called in very varied contexts. 313 * Keep the print routines usable in as many situations as possible 314 * by not using locking here. 315 */ 316 317 /* 318 * Ensure that preceding stores become visible to other CPUs 319 * before the flag. 320 */ 321 membar_producer(); 322 323 logsoftc.sc_need_wakeup = 1; 324} 325 326void 327logtick(void *arg) 328{ 329 if (!log_open) 330 return; 331 332 if (!logsoftc.sc_need_wakeup) 333 goto out; 334 logsoftc.sc_need_wakeup = 0; 335 336 /* 337 * sc_need_wakeup has to be cleared before handling the wakeup. 338 * This ensures that no wakeup is lost. 339 */ 340 membar_enter(); 341 342 selwakeup(&logsoftc.sc_selp); 343 if (logsoftc.sc_state & LOG_ASYNC) 344 csignal(logsoftc.sc_pgid, SIGIO, 345 logsoftc.sc_siguid, logsoftc.sc_sigeuid); 346 if (logsoftc.sc_state & LOG_RDWAIT) { 347 wakeup(msgbufp); 348 logsoftc.sc_state &= ~LOG_RDWAIT; 349 } 350out: 351 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 352} 353 354int 355logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 356{ 357 struct file *fp; 358 long l; 359 int error, s; 360 361 switch (com) { 362 363 /* return number of characters immediately available */ 364 case FIONREAD: 365 s = splhigh(); 366 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 367 splx(s); 368 if (l < 0) 369 l += msgbufp->msg_bufs; 370 *(int *)data = l; 371 break; 372 373 case FIONBIO: 374 break; 375 376 case FIOASYNC: 377 if (*(int *)data) 378 logsoftc.sc_state |= LOG_ASYNC; 379 else 380 logsoftc.sc_state &= ~LOG_ASYNC; 381 break; 382 383 case TIOCSPGRP: 384 logsoftc.sc_pgid = *(int *)data; 385 logsoftc.sc_siguid = p->p_ucred->cr_ruid; 386 logsoftc.sc_sigeuid = p->p_ucred->cr_uid; 387 break; 388 389 case TIOCGPGRP: 390 *(int *)data = logsoftc.sc_pgid; 391 break; 392 393 case LIOCSFD: 394 if ((error = suser(p)) != 0) 395 return (error); 396 fp = syslogf; 397 if ((error = getsock(p, *(int *)data, &syslogf)) != 0) 398 return (error); 399 if (fp) 400 FRELE(fp, p); 401 break; 402 403 default: 404 return (ENOTTY); 405 } 406 return (0); 407} 408 409int 410sys_sendsyslog(struct proc *p, void *v, register_t *retval) 411{ 412 struct sys_sendsyslog_args /* { 413 syscallarg(const char *) buf; 414 syscallarg(size_t) nbyte; 415 syscallarg(int) flags; 416 } */ *uap = v; 417 int error; 418 static int dropped_count, orig_error, orig_pid; 419 420 if (dropped_count) { 421 size_t l; 422 char buf[80]; 423 424 l = snprintf(buf, sizeof(buf), 425 "<%d>sendsyslog: dropped %d message%s, error %d, pid %d", 426 LOG_KERN|LOG_WARNING, dropped_count, 427 dropped_count == 1 ? "" : "s", orig_error, orig_pid); 428 error = dosendsyslog(p, buf, ulmin(l, sizeof(buf) - 1), 429 0, UIO_SYSSPACE); 430 if (error == 0) { 431 dropped_count = 0; 432 orig_error = 0; 433 orig_pid = 0; 434 } 435 } 436 error = dosendsyslog(p, SCARG(uap, buf), SCARG(uap, nbyte), 437 SCARG(uap, flags), UIO_USERSPACE); 438 if (error) { 439 dropped_count++; 440 orig_error = error; 441 orig_pid = p->p_p->ps_pid; 442 } 443 return (error); 444} 445 446int 447dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags, 448 enum uio_seg sflg) 449{ 450#ifdef KTRACE 451 struct iovec ktriov; 452#endif 453 struct file *fp; 454 char pri[6], *kbuf; 455 struct iovec aiov; 456 struct uio auio; 457 size_t i, len; 458 int error; 459 460 if (nbyte > LOG_MAXLINE) 461 nbyte = LOG_MAXLINE; 462 463 /* Global variable syslogf may change during sleep, use local copy. */ 464 fp = syslogf; 465 if (fp) 466 FREF(fp); 467 else if (!ISSET(flags, LOG_CONS)) 468 return (ENOTCONN); 469 else { 470 /* 471 * Strip off syslog priority when logging to console. 472 * LOG_PRIMASK | LOG_FACMASK is 0x03ff, so at most 4 473 * decimal digits may appear in priority as <1023>. 474 */ 475 len = MIN(nbyte, sizeof(pri)); 476 if (sflg == UIO_USERSPACE) { 477 if ((error = copyin(buf, pri, len))) 478 return (error); 479 } else 480 memcpy(pri, buf, len); 481 if (0 < len && pri[0] == '<') { 482 for (i = 1; i < len; i++) { 483 if (pri[i] < '0' || pri[i] > '9') 484 break; 485 } 486 if (i < len && pri[i] == '>') { 487 i++; 488 /* There must be at least one digit <0>. */ 489 if (i >= 3) { 490 buf += i; 491 nbyte -= i; 492 } 493 } 494 } 495 } 496 497 aiov.iov_base = (char *)buf; 498 aiov.iov_len = nbyte; 499 auio.uio_iov = &aiov; 500 auio.uio_iovcnt = 1; 501 auio.uio_segflg = sflg; 502 auio.uio_rw = UIO_WRITE; 503 auio.uio_procp = p; 504 auio.uio_offset = 0; 505 auio.uio_resid = aiov.iov_len; 506#ifdef KTRACE 507 if (sflg == UIO_USERSPACE && KTRPOINT(p, KTR_GENIO)) 508 ktriov = aiov; 509 else 510 ktriov.iov_len = 0; 511#endif 512 513 len = auio.uio_resid; 514 if (fp) { 515 int flags = (fp->f_flag & FNONBLOCK) ? MSG_DONTWAIT : 0; 516 error = sosend(fp->f_data, NULL, &auio, NULL, NULL, flags); 517 if (error == 0) 518 len -= auio.uio_resid; 519 } else if (constty || cn_devvp) { 520 error = cnwrite(0, &auio, 0); 521 if (error == 0) 522 len -= auio.uio_resid; 523 aiov.iov_base = "\r\n"; 524 aiov.iov_len = 2; 525 auio.uio_iov = &aiov; 526 auio.uio_iovcnt = 1; 527 auio.uio_segflg = UIO_SYSSPACE; 528 auio.uio_rw = UIO_WRITE; 529 auio.uio_procp = p; 530 auio.uio_offset = 0; 531 auio.uio_resid = aiov.iov_len; 532 cnwrite(0, &auio, 0); 533 } else { 534 /* XXX console redirection breaks down... */ 535 if (sflg == UIO_USERSPACE) { 536 kbuf = malloc(len, M_TEMP, M_WAITOK); 537 error = copyin(aiov.iov_base, kbuf, len); 538 } else { 539 kbuf = aiov.iov_base; 540 error = 0; 541 } 542 if (error == 0) 543 for (i = 0; i < len; i++) { 544 if (kbuf[i] == '\0') 545 break; 546 cnputc(kbuf[i]); 547 auio.uio_resid--; 548 } 549 if (sflg == UIO_USERSPACE) 550 free(kbuf, M_TEMP, len); 551 if (error == 0) 552 len -= auio.uio_resid; 553 cnputc('\n'); 554 } 555 556#ifdef KTRACE 557 if (error == 0 && ktriov.iov_len != 0) 558 ktrgenio(p, -1, UIO_WRITE, &ktriov, len); 559#endif 560 if (fp) 561 FRELE(fp, p); 562 else 563 error = ENOTCONN; 564 return (error); 565} 566