1 /* $OpenBSD: subr_log.c,v 1.66 2020/04/07 13:27:51 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 mbp->msg_bufl = lmin(mbp->msg_bufl+1, mbp->msg_bufs); 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 int 167 logopen(dev_t dev, int flags, int mode, struct proc *p) 168 { 169 if (log_open) 170 return (EBUSY); 171 log_open = 1; 172 sigio_init(&logsoftc.sc_sigio); 173 timeout_set(&logsoftc.sc_tick, logtick, NULL); 174 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 175 return (0); 176 } 177 178 int 179 logclose(dev_t dev, int flag, int mode, struct proc *p) 180 { 181 struct file *fp; 182 183 fp = syslogf; 184 syslogf = NULL; 185 if (fp) 186 FRELE(fp, p); 187 log_open = 0; 188 timeout_del(&logsoftc.sc_tick); 189 logsoftc.sc_state = 0; 190 sigio_free(&logsoftc.sc_sigio); 191 return (0); 192 } 193 194 int 195 logread(dev_t dev, struct uio *uio, int flag) 196 { 197 struct msgbuf *mbp = msgbufp; 198 size_t l; 199 int s, error = 0; 200 201 s = splhigh(); 202 while (mbp->msg_bufr == mbp->msg_bufx) { 203 if (flag & IO_NDELAY) { 204 error = EWOULDBLOCK; 205 goto out; 206 } 207 logsoftc.sc_state |= LOG_RDWAIT; 208 error = tsleep_nsec(mbp, LOG_RDPRI | PCATCH, "klog", INFSLP); 209 if (error) 210 goto out; 211 } 212 logsoftc.sc_state &= ~LOG_RDWAIT; 213 214 if (mbp->msg_bufd > 0) { 215 char buf[64]; 216 217 l = snprintf(buf, sizeof(buf), 218 "<%d>klog: dropped %ld byte%s, message buffer full\n", 219 LOG_KERN|LOG_WARNING, mbp->msg_bufd, 220 mbp->msg_bufd == 1 ? "" : "s"); 221 error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio); 222 if (error) 223 goto out; 224 mbp->msg_bufd = 0; 225 } 226 227 while (uio->uio_resid > 0) { 228 if (mbp->msg_bufx >= mbp->msg_bufr) 229 l = mbp->msg_bufx - mbp->msg_bufr; 230 else 231 l = mbp->msg_bufs - mbp->msg_bufr; 232 l = ulmin(l, uio->uio_resid); 233 if (l == 0) 234 break; 235 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], l, uio); 236 if (error) 237 break; 238 mbp->msg_bufr += l; 239 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 240 mbp->msg_bufr = 0; 241 } 242 out: 243 splx(s); 244 return (error); 245 } 246 247 int 248 logpoll(dev_t dev, int events, struct proc *p) 249 { 250 int s, revents = 0; 251 252 s = splhigh(); 253 if (events & (POLLIN | POLLRDNORM)) { 254 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 255 revents |= events & (POLLIN | POLLRDNORM); 256 else 257 selrecord(p, &logsoftc.sc_selp); 258 } 259 splx(s); 260 return (revents); 261 } 262 263 int 264 logkqfilter(dev_t dev, struct knote *kn) 265 { 266 struct klist *klist; 267 int s; 268 269 switch (kn->kn_filter) { 270 case EVFILT_READ: 271 klist = &logsoftc.sc_selp.si_note; 272 kn->kn_fop = &logread_filtops; 273 break; 274 default: 275 return (EINVAL); 276 } 277 278 kn->kn_hook = (void *)msgbufp; 279 280 s = splhigh(); 281 klist_insert(klist, kn); 282 splx(s); 283 284 return (0); 285 } 286 287 void 288 filt_logrdetach(struct knote *kn) 289 { 290 int s; 291 292 s = splhigh(); 293 klist_remove(&logsoftc.sc_selp.si_note, kn); 294 splx(s); 295 } 296 297 int 298 filt_logread(struct knote *kn, long hint) 299 { 300 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 301 int s, event = 0; 302 303 s = splhigh(); 304 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 305 event = (p->msg_bufx != p->msg_bufr); 306 splx(s); 307 return (event); 308 } 309 310 void 311 logwakeup(void) 312 { 313 /* 314 * The actual wakeup has to be deferred because logwakeup() can be 315 * called in very varied contexts. 316 * Keep the print routines usable in as many situations as possible 317 * by not using locking here. 318 */ 319 320 /* 321 * Ensure that preceding stores become visible to other CPUs 322 * before the flag. 323 */ 324 membar_producer(); 325 326 logsoftc.sc_need_wakeup = 1; 327 } 328 329 void 330 logtick(void *arg) 331 { 332 if (!log_open) 333 return; 334 335 if (!logsoftc.sc_need_wakeup) 336 goto out; 337 logsoftc.sc_need_wakeup = 0; 338 339 /* 340 * sc_need_wakeup has to be cleared before handling the wakeup. 341 * This ensures that no wakeup is lost. 342 */ 343 membar_enter(); 344 345 selwakeup(&logsoftc.sc_selp); 346 if (logsoftc.sc_state & LOG_ASYNC) 347 pgsigio(&logsoftc.sc_sigio, SIGIO, 0); 348 if (logsoftc.sc_state & LOG_RDWAIT) { 349 wakeup(msgbufp); 350 logsoftc.sc_state &= ~LOG_RDWAIT; 351 } 352 out: 353 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 354 } 355 356 int 357 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 358 { 359 struct file *fp; 360 long l; 361 int error, s; 362 363 switch (com) { 364 365 /* return number of characters immediately available */ 366 case FIONREAD: 367 s = splhigh(); 368 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 369 splx(s); 370 if (l < 0) 371 l += msgbufp->msg_bufs; 372 *(int *)data = l; 373 break; 374 375 case FIONBIO: 376 break; 377 378 case FIOASYNC: 379 if (*(int *)data) 380 logsoftc.sc_state |= LOG_ASYNC; 381 else 382 logsoftc.sc_state &= ~LOG_ASYNC; 383 break; 384 385 case FIOSETOWN: 386 case TIOCSPGRP: 387 return (sigio_setown(&logsoftc.sc_sigio, com, data)); 388 389 case FIOGETOWN: 390 case TIOCGPGRP: 391 sigio_getown(&logsoftc.sc_sigio, com, data); 392 break; 393 394 case LIOCSFD: 395 if ((error = suser(p)) != 0) 396 return (error); 397 fp = syslogf; 398 if ((error = getsock(p, *(int *)data, &syslogf)) != 0) 399 return (error); 400 if (fp) 401 FRELE(fp, p); 402 break; 403 404 default: 405 return (ENOTTY); 406 } 407 return (0); 408 } 409 410 int 411 sys_sendsyslog(struct proc *p, void *v, register_t *retval) 412 { 413 struct sys_sendsyslog_args /* { 414 syscallarg(const char *) buf; 415 syscallarg(size_t) nbyte; 416 syscallarg(int) flags; 417 } */ *uap = v; 418 int error; 419 static int dropped_count, orig_error, orig_pid; 420 421 if (dropped_count) { 422 size_t l; 423 char buf[80]; 424 425 l = snprintf(buf, sizeof(buf), 426 "<%d>sendsyslog: dropped %d message%s, error %d, pid %d", 427 LOG_KERN|LOG_WARNING, dropped_count, 428 dropped_count == 1 ? "" : "s", orig_error, orig_pid); 429 error = dosendsyslog(p, buf, ulmin(l, sizeof(buf) - 1), 430 0, UIO_SYSSPACE); 431 if (error == 0) { 432 dropped_count = 0; 433 orig_error = 0; 434 orig_pid = 0; 435 } 436 } 437 error = dosendsyslog(p, SCARG(uap, buf), SCARG(uap, nbyte), 438 SCARG(uap, flags), UIO_USERSPACE); 439 if (error) { 440 dropped_count++; 441 orig_error = error; 442 orig_pid = p->p_p->ps_pid; 443 } 444 return (error); 445 } 446 447 int 448 dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags, 449 enum uio_seg sflg) 450 { 451 #ifdef KTRACE 452 struct iovec ktriov; 453 #endif 454 struct file *fp; 455 char pri[6], *kbuf; 456 struct iovec aiov; 457 struct uio auio; 458 size_t i, len; 459 int error; 460 461 if (nbyte > LOG_MAXLINE) 462 nbyte = LOG_MAXLINE; 463 464 /* Global variable syslogf may change during sleep, use local copy. */ 465 fp = syslogf; 466 if (fp) 467 FREF(fp); 468 else if (!ISSET(flags, LOG_CONS)) 469 return (ENOTCONN); 470 else { 471 /* 472 * Strip off syslog priority when logging to console. 473 * LOG_PRIMASK | LOG_FACMASK is 0x03ff, so at most 4 474 * decimal digits may appear in priority as <1023>. 475 */ 476 len = MIN(nbyte, sizeof(pri)); 477 if (sflg == UIO_USERSPACE) { 478 if ((error = copyin(buf, pri, len))) 479 return (error); 480 } else 481 memcpy(pri, buf, len); 482 if (0 < len && pri[0] == '<') { 483 for (i = 1; i < len; i++) { 484 if (pri[i] < '0' || pri[i] > '9') 485 break; 486 } 487 if (i < len && pri[i] == '>') { 488 i++; 489 /* There must be at least one digit <0>. */ 490 if (i >= 3) { 491 buf += i; 492 nbyte -= i; 493 } 494 } 495 } 496 } 497 498 aiov.iov_base = (char *)buf; 499 aiov.iov_len = nbyte; 500 auio.uio_iov = &aiov; 501 auio.uio_iovcnt = 1; 502 auio.uio_segflg = sflg; 503 auio.uio_rw = UIO_WRITE; 504 auio.uio_procp = p; 505 auio.uio_offset = 0; 506 auio.uio_resid = aiov.iov_len; 507 #ifdef KTRACE 508 if (sflg == UIO_USERSPACE && KTRPOINT(p, KTR_GENIO)) 509 ktriov = aiov; 510 else 511 ktriov.iov_len = 0; 512 #endif 513 514 len = auio.uio_resid; 515 if (fp) { 516 int flags = (fp->f_flag & FNONBLOCK) ? MSG_DONTWAIT : 0; 517 error = sosend(fp->f_data, NULL, &auio, NULL, NULL, flags); 518 if (error == 0) 519 len -= auio.uio_resid; 520 } else if (constty || cn_devvp) { 521 error = cnwrite(0, &auio, 0); 522 if (error == 0) 523 len -= auio.uio_resid; 524 aiov.iov_base = "\r\n"; 525 aiov.iov_len = 2; 526 auio.uio_iov = &aiov; 527 auio.uio_iovcnt = 1; 528 auio.uio_segflg = UIO_SYSSPACE; 529 auio.uio_rw = UIO_WRITE; 530 auio.uio_procp = p; 531 auio.uio_offset = 0; 532 auio.uio_resid = aiov.iov_len; 533 cnwrite(0, &auio, 0); 534 } else { 535 /* XXX console redirection breaks down... */ 536 if (sflg == UIO_USERSPACE) { 537 kbuf = malloc(len, M_TEMP, M_WAITOK); 538 error = copyin(aiov.iov_base, kbuf, len); 539 } else { 540 kbuf = aiov.iov_base; 541 error = 0; 542 } 543 if (error == 0) 544 for (i = 0; i < len; i++) { 545 if (kbuf[i] == '\0') 546 break; 547 cnputc(kbuf[i]); 548 auio.uio_resid--; 549 } 550 if (sflg == UIO_USERSPACE) 551 free(kbuf, M_TEMP, len); 552 if (error == 0) 553 len -= auio.uio_resid; 554 cnputc('\n'); 555 } 556 557 #ifdef KTRACE 558 if (error == 0 && ktriov.iov_len != 0) 559 ktrgenio(p, -1, UIO_WRITE, &ktriov, len); 560 #endif 561 if (fp) 562 FRELE(fp, p); 563 else 564 error = ENOTCONN; 565 return (error); 566 } 567