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