1 /* $OpenBSD: subr_log.c,v 1.59 2019/10/24 03:31: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 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 82 int log_open; /* also used in log() */ 83 int msgbufmapped; /* is the message buffer mapped */ 84 struct msgbuf *msgbufp; /* the mapped buffer, itself. */ 85 struct msgbuf *consbufp; /* console message buffer. */ 86 struct file *syslogf; 87 88 void filt_logrdetach(struct knote *kn); 89 int filt_logread(struct knote *kn, long hint); 90 91 struct filterops logread_filtops = 92 { 1, NULL, filt_logrdetach, filt_logread}; 93 94 int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg); 95 void logtick(void *); 96 97 void 98 initmsgbuf(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 132 void 133 initconsbuf(void) 134 { 135 long new_bufs; 136 137 /* Set up a buffer to collect /dev/console output */ 138 consbufp = malloc(CONSBUFSIZE, M_TEMP, M_NOWAIT|M_ZERO); 139 if (consbufp) { 140 new_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc); 141 consbufp->msg_magic = MSG_MAGIC; 142 consbufp->msg_bufs = new_bufs; 143 } 144 } 145 146 void 147 msgbuf_putchar(struct msgbuf *mbp, const char c) 148 { 149 int s; 150 151 if (mbp->msg_magic != MSG_MAGIC) 152 /* Nothing we can do */ 153 return; 154 155 s = splhigh(); 156 mbp->msg_bufc[mbp->msg_bufx++] = c; 157 mbp->msg_bufl = lmin(mbp->msg_bufl+1, mbp->msg_bufs); 158 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs) 159 mbp->msg_bufx = 0; 160 /* If the buffer is full, keep the most recent data. */ 161 if (mbp->msg_bufr == mbp->msg_bufx) { 162 if (++mbp->msg_bufr >= mbp->msg_bufs) 163 mbp->msg_bufr = 0; 164 mbp->msg_bufd++; 165 } 166 splx(s); 167 } 168 169 int 170 logopen(dev_t dev, int flags, int mode, struct proc *p) 171 { 172 if (log_open) 173 return (EBUSY); 174 log_open = 1; 175 timeout_set(&logsoftc.sc_tick, logtick, NULL); 176 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 177 return (0); 178 } 179 180 int 181 logclose(dev_t dev, int flag, int mode, struct proc *p) 182 { 183 struct file *fp; 184 185 fp = syslogf; 186 syslogf = NULL; 187 if (fp) 188 FRELE(fp, p); 189 log_open = 0; 190 timeout_del(&logsoftc.sc_tick); 191 logsoftc.sc_state = 0; 192 return (0); 193 } 194 195 int 196 logread(dev_t dev, struct uio *uio, int flag) 197 { 198 struct msgbuf *mbp = msgbufp; 199 size_t l; 200 int s, error = 0; 201 202 s = splhigh(); 203 while (mbp->msg_bufr == mbp->msg_bufx) { 204 if (flag & IO_NDELAY) { 205 error = EWOULDBLOCK; 206 goto out; 207 } 208 logsoftc.sc_state |= LOG_RDWAIT; 209 error = tsleep(mbp, LOG_RDPRI | PCATCH, 210 "klog", 0); 211 if (error) 212 goto out; 213 } 214 logsoftc.sc_state &= ~LOG_RDWAIT; 215 216 if (mbp->msg_bufd > 0) { 217 char buf[64]; 218 219 l = snprintf(buf, sizeof(buf), 220 "<%d>klog: dropped %ld byte%s, message buffer full\n", 221 LOG_KERN|LOG_WARNING, mbp->msg_bufd, 222 mbp->msg_bufd == 1 ? "" : "s"); 223 error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio); 224 if (error) 225 goto out; 226 mbp->msg_bufd = 0; 227 } 228 229 while (uio->uio_resid > 0) { 230 if (mbp->msg_bufx >= mbp->msg_bufr) 231 l = mbp->msg_bufx - mbp->msg_bufr; 232 else 233 l = mbp->msg_bufs - mbp->msg_bufr; 234 l = ulmin(l, uio->uio_resid); 235 if (l == 0) 236 break; 237 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], l, uio); 238 if (error) 239 break; 240 mbp->msg_bufr += l; 241 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs) 242 mbp->msg_bufr = 0; 243 } 244 out: 245 splx(s); 246 return (error); 247 } 248 249 int 250 logpoll(dev_t dev, int events, struct proc *p) 251 { 252 int s, revents = 0; 253 254 s = splhigh(); 255 if (events & (POLLIN | POLLRDNORM)) { 256 if (msgbufp->msg_bufr != msgbufp->msg_bufx) 257 revents |= events & (POLLIN | POLLRDNORM); 258 else 259 selrecord(p, &logsoftc.sc_selp); 260 } 261 splx(s); 262 return (revents); 263 } 264 265 int 266 logkqfilter(dev_t dev, struct knote *kn) 267 { 268 struct klist *klist; 269 int s; 270 271 switch (kn->kn_filter) { 272 case EVFILT_READ: 273 klist = &logsoftc.sc_selp.si_note; 274 kn->kn_fop = &logread_filtops; 275 break; 276 default: 277 return (EINVAL); 278 } 279 280 kn->kn_hook = (void *)msgbufp; 281 282 s = splhigh(); 283 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 284 splx(s); 285 286 return (0); 287 } 288 289 void 290 filt_logrdetach(struct knote *kn) 291 { 292 int s; 293 294 s = splhigh(); 295 SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext); 296 splx(s); 297 } 298 299 int 300 filt_logread(struct knote *kn, long hint) 301 { 302 struct msgbuf *p = (struct msgbuf *)kn->kn_hook; 303 int s, event = 0; 304 305 s = splhigh(); 306 kn->kn_data = (int)(p->msg_bufx - p->msg_bufr); 307 event = (p->msg_bufx != p->msg_bufr); 308 splx(s); 309 return (event); 310 } 311 312 void 313 logwakeup(void) 314 { 315 /* 316 * The actual wakeup has to be deferred because logwakeup() can be 317 * called in very varied contexts. 318 * Keep the print routines usable in as many situations as possible 319 * by not using locking here. 320 */ 321 322 /* 323 * Ensure that preceding stores become visible to other CPUs 324 * before the flag. 325 */ 326 membar_producer(); 327 328 logsoftc.sc_need_wakeup = 1; 329 } 330 331 void 332 logtick(void *arg) 333 { 334 if (!log_open) 335 return; 336 337 if (!logsoftc.sc_need_wakeup) 338 goto out; 339 logsoftc.sc_need_wakeup = 0; 340 341 /* 342 * sc_need_wakeup has to be cleared before handling the wakeup. 343 * This ensures that no wakeup is lost. 344 */ 345 membar_enter(); 346 347 selwakeup(&logsoftc.sc_selp); 348 if (logsoftc.sc_state & LOG_ASYNC) 349 csignal(logsoftc.sc_pgid, SIGIO, 350 logsoftc.sc_siguid, logsoftc.sc_sigeuid); 351 if (logsoftc.sc_state & LOG_RDWAIT) { 352 wakeup(msgbufp); 353 logsoftc.sc_state &= ~LOG_RDWAIT; 354 } 355 out: 356 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK); 357 } 358 359 int 360 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p) 361 { 362 struct file *fp; 363 long l; 364 int error, s; 365 366 switch (com) { 367 368 /* return number of characters immediately available */ 369 case FIONREAD: 370 s = splhigh(); 371 l = msgbufp->msg_bufx - msgbufp->msg_bufr; 372 splx(s); 373 if (l < 0) 374 l += msgbufp->msg_bufs; 375 *(int *)data = l; 376 break; 377 378 case FIONBIO: 379 break; 380 381 case FIOASYNC: 382 if (*(int *)data) 383 logsoftc.sc_state |= LOG_ASYNC; 384 else 385 logsoftc.sc_state &= ~LOG_ASYNC; 386 break; 387 388 case TIOCSPGRP: 389 logsoftc.sc_pgid = *(int *)data; 390 logsoftc.sc_siguid = p->p_ucred->cr_ruid; 391 logsoftc.sc_sigeuid = p->p_ucred->cr_uid; 392 break; 393 394 case TIOCGPGRP: 395 *(int *)data = logsoftc.sc_pgid; 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