xref: /openbsd-src/sys/kern/subr_log.c (revision 47911bd667ac77dc523b8a13ef40b012dbffa741)
1 /*	$OpenBSD: subr_log.c,v 1.8 2002/06/29 02:58:14 mickey 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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)subr_log.c	8.1 (Berkeley) 6/10/93
37  */
38 
39 /*
40  * Error log buffer for kernel printf's.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46 #include <sys/vnode.h>
47 #include <sys/ioctl.h>
48 #include <sys/msgbuf.h>
49 #include <sys/file.h>
50 #include <sys/signalvar.h>
51 #include <sys/syslog.h>
52 #include <sys/conf.h>
53 
54 #define LOG_RDPRI	(PZERO + 1)
55 
56 #define LOG_ASYNC	0x04
57 #define LOG_RDWAIT	0x08
58 
59 struct logsoftc {
60 	int	sc_state;		/* see above for possibilities */
61 	struct	selinfo sc_selp;	/* process waiting on select call */
62 	int	sc_pgid;		/* process/group for async I/O */
63 	uid_t	sc_siguid;		/* uid for process that set sc_pgid */
64 	uid_t	sc_sigeuid;		/* euid for process that set sc_pgid */
65 } logsoftc;
66 
67 int	log_open;			/* also used in log() */
68 int	msgbufmapped;			/* is the message buffer mapped */
69 int	msgbufenabled;			/* is logging to the buffer enabled */
70 struct	msgbuf *msgbufp;		/* the mapped buffer, itself. */
71 
72 void filt_logrdetach(struct knote *kn);
73 int filt_logread(struct knote *kn, long hint);
74 
75 struct filterops logread_filtops =
76 	{ 1, NULL, filt_logrdetach, filt_logread};
77 
78 void
79 initmsgbuf(buf, bufsize)
80 	caddr_t buf;
81 	size_t bufsize;
82 {
83 	register struct msgbuf *mbp;
84 	long new_bufs;
85 
86 	/* Sanity-check the given size. */
87 	if (bufsize < sizeof(struct msgbuf))
88 		return;
89 
90 	mbp = msgbufp = (struct msgbuf *)buf;
91 
92 	new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc);
93 	if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) ||
94 	    (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) ||
95 	    (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) {
96 		/*
97 		 * If the buffer magic number is wrong, has changed
98 		 * size (which shouldn't happen often), or is
99 		 * internally inconsistent, initialize it.
100 		 */
101 
102 		bzero(buf, bufsize);
103 		mbp->msg_magic = MSG_MAGIC;
104 		mbp->msg_bufs = new_bufs;
105 	}
106 
107 	/* mark it as ready for use. */
108 	msgbufmapped = msgbufenabled = 1;
109 }
110 
111 /*ARGSUSED*/
112 int
113 logopen(dev, flags, mode, p)
114 	dev_t dev;
115 	int flags, mode;
116 	struct proc *p;
117 {
118 	if (log_open)
119 		return (EBUSY);
120 	log_open = 1;
121 	return (0);
122 }
123 
124 /*ARGSUSED*/
125 int
126 logclose(dev, flag, mode, p)
127 	dev_t dev;
128 	int flag, mode;
129 	struct proc *p;
130 {
131 
132 	log_open = 0;
133 	logsoftc.sc_state = 0;
134 	return (0);
135 }
136 
137 /*ARGSUSED*/
138 int
139 logread(dev, uio, flag)
140 	dev_t dev;
141 	struct uio *uio;
142 	int flag;
143 {
144 	register struct msgbuf *mbp = msgbufp;
145 	register long l;
146 	register int s;
147 	int error = 0;
148 
149 	s = splhigh();
150 	while (mbp->msg_bufr == mbp->msg_bufx) {
151 		if (flag & IO_NDELAY) {
152 			splx(s);
153 			return (EWOULDBLOCK);
154 		}
155 		logsoftc.sc_state |= LOG_RDWAIT;
156 		error = tsleep((caddr_t)mbp, LOG_RDPRI | PCATCH,
157 			       "klog", 0);
158 		if (error) {
159 			splx(s);
160 			return (error);
161 		}
162 	}
163 	splx(s);
164 	logsoftc.sc_state &= ~LOG_RDWAIT;
165 
166 	while (uio->uio_resid > 0) {
167 		l = mbp->msg_bufx - mbp->msg_bufr;
168 		if (l < 0)
169 			l = mbp->msg_bufs - mbp->msg_bufr;
170 		l = min(l, uio->uio_resid);
171 		if (l == 0)
172 			break;
173 		error = uiomove((caddr_t)&mbp->msg_bufc[mbp->msg_bufr],
174 			(int)l, uio);
175 		if (error)
176 			break;
177 		mbp->msg_bufr += l;
178 		if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs)
179 			mbp->msg_bufr = 0;
180 	}
181 	return (error);
182 }
183 
184 /*ARGSUSED*/
185 int
186 logselect(dev, rw, p)
187 	dev_t dev;
188 	int rw;
189 	struct proc *p;
190 {
191 	int s = splhigh();
192 
193 	switch (rw) {
194 
195 	case FREAD:
196 		if (msgbufp->msg_bufr != msgbufp->msg_bufx) {
197 			splx(s);
198 			return (1);
199 		}
200 		selrecord(p, &logsoftc.sc_selp);
201 		break;
202 	}
203 	splx(s);
204 	return (0);
205 }
206 
207 int
208 logkqfilter(dev_t dev, struct knote *kn)
209 {
210 	struct klist *klist;
211 	int s;
212 
213 	switch (kn->kn_filter) {
214 	case EVFILT_READ:
215 		klist = &logsoftc.sc_selp.si_note;
216 		kn->kn_fop = &logread_filtops;
217 		break;
218 	default:
219 		return (1);
220 	}
221 
222 	kn->kn_hook = (void *)msgbufp;
223 
224 	s = splhigh();
225 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
226 	splx(s);
227 
228 	return (0);
229 }
230 
231 void
232 filt_logrdetach(struct knote *kn)
233 {
234 	int s = splhigh();
235 
236 	SLIST_REMOVE(&logsoftc.sc_selp.si_note, kn, knote, kn_selnext);
237 	splx(s);
238 }
239 
240 int
241 filt_logread(struct knote *kn, long hint)
242 {
243 	struct  msgbuf *p = (struct  msgbuf *)kn->kn_hook;
244 
245 	kn->kn_data = (int)(p->msg_bufx - p->msg_bufr);
246 
247 	return (p->msg_bufx != p->msg_bufr);
248 }
249 
250 void
251 logwakeup()
252 {
253 	if (!log_open)
254 		return;
255 	selwakeup(&logsoftc.sc_selp);
256 	if (logsoftc.sc_state & LOG_ASYNC)
257 		csignal(logsoftc.sc_pgid, SIGIO,
258 		    logsoftc.sc_siguid, logsoftc.sc_sigeuid);
259 	if (logsoftc.sc_state & LOG_RDWAIT) {
260 		wakeup((caddr_t)msgbufp);
261 		logsoftc.sc_state &= ~LOG_RDWAIT;
262 	}
263 	KNOTE(&logsoftc.sc_selp.si_note, 0);
264 }
265 
266 /*ARGSUSED*/
267 int
268 logioctl(dev, com, data, flag, p)
269 	dev_t dev;
270 	u_long com;
271 	caddr_t data;
272 	int flag;
273 	struct proc *p;
274 {
275 	long l;
276 	int s;
277 
278 	switch (com) {
279 
280 	/* return number of characters immediately available */
281 	case FIONREAD:
282 		s = splhigh();
283 		l = msgbufp->msg_bufx - msgbufp->msg_bufr;
284 		splx(s);
285 		if (l < 0)
286 			l += msgbufp->msg_bufs;
287 		*(int *)data = l;
288 		break;
289 
290 	case FIONBIO:
291 		break;
292 
293 	case FIOASYNC:
294 		if (*(int *)data)
295 			logsoftc.sc_state |= LOG_ASYNC;
296 		else
297 			logsoftc.sc_state &= ~LOG_ASYNC;
298 		break;
299 
300 	case TIOCSPGRP:
301 		logsoftc.sc_pgid = *(int *)data;
302 		logsoftc.sc_siguid = p->p_cred->p_ruid;
303 		logsoftc.sc_sigeuid = p->p_ucred->cr_uid;
304 		break;
305 
306 	case TIOCGPGRP:
307 		*(int *)data = logsoftc.sc_pgid;
308 		break;
309 
310 	default:
311 		return (-1);
312 	}
313 	return (0);
314 }
315