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