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