1 /* $OpenBSD: subr_log.c,v 1.67 2020/08/18 13:38:24 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 99 void 100 initmsgbuf(caddr_t buf, size_t bufsize) 101 { 102 struct msgbuf *mbp; 103 long new_bufs; 104 105 /* Sanity-check the given size. */ 106 if (bufsize < sizeof(struct msgbuf)) 107 return; 108 109 mbp = msgbufp = (struct msgbuf *)buf; 110 111 new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc); 112 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) || 113 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) || 114 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) { 115 /* 116 * If the buffer magic number is wrong, has changed 117 * size (which shouldn't happen often), or is 118 * internally inconsistent, initialize it. 119 */ 120 121 memset(buf, 0, bufsize); 122 mbp->msg_magic = MSG_MAGIC; 123 mbp->msg_bufs = new_bufs; 124 } 125 126 /* Always start new buffer data on a new line. */ 127 if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n') 128 msgbuf_putchar(msgbufp, '\n'); 129 130 /* mark it as ready for use. */ 131 msgbufmapped = 1; 132 } 133 134 void 135 initconsbuf(void) 136 { 137 /* Set up a buffer to collect /dev/console output */ 138 consbufp = malloc(CONSBUFSIZE, M_TTYS, M_WAITOK | M_ZERO); 139 consbufp->msg_magic = MSG_MAGIC; 140 consbufp->msg_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc); 141 } 142 143 void 144 msgbuf_putchar(struct msgbuf *mbp, const char c) 145 { 146 int s; 147 148 if (mbp->msg_magic != MSG_MAGIC) 149 /* Nothing we can do */ 150 return; 151 152 s = splhigh(); 153 mbp->msg_bufc[mbp->msg_bufx++] = c; 154 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs) 155 mbp->msg_bufx = 0; 156 /* If the buffer is full, keep the most recent data. */ 157 if (mbp->msg_bufr == mbp->msg_bufx) { 158 if (++mbp->msg_bufr >= mbp->msg_bufs) 159 mbp->msg_bufr = 0; 160 mbp->msg_bufd++; 161 } 162 splx(s); 163 } 164 165 int 166 logopen(dev_t dev, int flags, int mode, struct proc *p) 167 { 168 if (log_open) 169 return (EBUSY); 170 log_open = 1; 171 sigio_init(&logsoftc.sc_sigio); 172 timeout_set(&logsoftc.sc_tick, logtick, NULL); 173 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 174 return (0); 175 } 176 177 int 178 logclose(dev_t dev, int flag, int mode, struct proc *p) 179 { 180 struct file *fp; 181 182 fp = syslogf; 183 syslogf = NULL; 184 if (fp) 185 FRELE(fp, p); 186 log_open = 0; 187 timeout_del(&logsoftc.sc_tick); 188 logsoftc.sc_state = 0; 189 sigio_free(&logsoftc.sc_sigio); 190 return (0); 191 } 192 193 int 194 logread(dev_t dev, struct uio *uio, int flag) 195 { 196 struct msgbuf *mbp = msgbufp; 197 size_t l; 198 int s, error = 0; 199 200 s = splhigh(); 201 while (mbp->msg_bufr == mbp->msg_bufx) { 202 if (flag & IO_NDELAY) { 203 error = EWOULDBLOCK; 204 goto out; 205 } 206 logsoftc.sc_state |= LOG_RDWAIT; 207 error = tsleep_nsec(mbp, LOG_RDPRI | PCATCH, "klog", INFSLP); 208 if (error) 209 goto out; 210 } 211 logsoftc.sc_state &= ~LOG_RDWAIT; 212 213 if (mbp->msg_bufd > 0) { 214 char buf[64]; 215 216 l = snprintf(buf, sizeof(buf), 217 "<%d>klog: dropped %ld byte%s, message buffer full\n", 218 LOG_KERN|LOG_WARNING, mbp->msg_bufd, 219 mbp->msg_bufd == 1 ? "" : "s"); 220 error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio); 221 if (error) 222 goto out; 223 mbp->msg_bufd = 0; 224 } 225 226 while (uio->uio_resid > 0) { 227 if (mbp->msg_bufx >= mbp->msg_bufr) 228 l = mbp->msg_bufx - mbp->msg_bufr; 229 else 230 l = mbp->msg_bufs - mbp->msg_bufr; 231 l = ulmin(l, uio->uio_resid); 232 if (l == 0) 233 break; 234 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], l, uio); 235 if (error) 236 break; 237 mbp->msg_bufr += l; 238 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 239 mbp->msg_bufr = 0; 240 } 241 out: 242 splx(s); 243 return (error); 244 } 245 246 int 247 logpoll(dev_t dev, int events, struct proc *p) 248 { 249 int s, revents = 0; 250 251 s = splhigh(); 252 if (events & (POLLIN | POLLRDNORM)) { 253 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 254 revents |= events & (POLLIN | POLLRDNORM); 255 else 256 selrecord(p, &logsoftc.sc_selp); 257 } 258 splx(s); 259 return (revents); 260 } 261 262 int 263 logkqfilter(dev_t dev, struct knote *kn) 264 { 265 struct klist *klist; 266 int s; 267 268 switch (kn->kn_filter) { 269 case EVFILT_READ: 270 klist = &logsoftc.sc_selp.si_note; 271 kn->kn_fop = &logread_filtops; 272 break; 273 default: 274 return (EINVAL); 275 } 276 277 kn->kn_hook = (void *)msgbufp; 278 279 s = splhigh(); 280 klist_insert(klist, kn); 281 splx(s); 282 283 return (0); 284 } 285 286 void 287 filt_logrdetach(struct knote *kn) 288 { 289 int s; 290 291 s = splhigh(); 292 klist_remove(&logsoftc.sc_selp.si_note, kn); 293 splx(s); 294 } 295 296 int 297 filt_logread(struct knote *kn, long hint) 298 { 299 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 300 int s, event = 0; 301 302 s = splhigh(); 303 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 304 event = (p->msg_bufx != p->msg_bufr); 305 splx(s); 306 return (event); 307 } 308 309 void 310 logwakeup(void) 311 { 312 /* 313 * The actual wakeup has to be deferred because logwakeup() can be 314 * called in very varied contexts. 315 * Keep the print routines usable in as many situations as possible 316 * by not using locking here. 317 */ 318 319 /* 320 * Ensure that preceding stores become visible to other CPUs 321 * before the flag. 322 */ 323 membar_producer(); 324 325 logsoftc.sc_need_wakeup = 1; 326 } 327 328 void 329 logtick(void *arg) 330 { 331 if (!log_open) 332 return; 333 334 if (!logsoftc.sc_need_wakeup) 335 goto out; 336 logsoftc.sc_need_wakeup = 0; 337 338 /* 339 * sc_need_wakeup has to be cleared before handling the wakeup. 340 * This ensures that no wakeup is lost. 341 */ 342 membar_enter(); 343 344 selwakeup(&logsoftc.sc_selp); 345 if (logsoftc.sc_state & LOG_ASYNC) 346 pgsigio(&logsoftc.sc_sigio, SIGIO, 0); 347 if (logsoftc.sc_state & LOG_RDWAIT) { 348 wakeup(msgbufp); 349 logsoftc.sc_state &= ~LOG_RDWAIT; 350 } 351 out: 352 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 353 } 354 355 int 356 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 357 { 358 struct file *fp; 359 long l; 360 int error, s; 361 362 switch (com) { 363 364 /* return number of characters immediately available */ 365 case FIONREAD: 366 s = splhigh(); 367 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 368 splx(s); 369 if (l < 0) 370 l += msgbufp->msg_bufs; 371 *(int *)data = l; 372 break; 373 374 case FIONBIO: 375 break; 376 377 case FIOASYNC: 378 if (*(int *)data) 379 logsoftc.sc_state |= LOG_ASYNC; 380 else 381 logsoftc.sc_state &= ~LOG_ASYNC; 382 break; 383 384 case FIOSETOWN: 385 case TIOCSPGRP: 386 return (sigio_setown(&logsoftc.sc_sigio, com, data)); 387 388 case FIOGETOWN: 389 case TIOCGPGRP: 390 sigio_getown(&logsoftc.sc_sigio, com, data); 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 409 int 410 sys_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 446 int 447 dosendsyslog(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