subr_log.c revision 1.8
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
59struct 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
67int	log_open;			/* also used in log() */
68int	msgbufmapped;			/* is the message buffer mapped */
69int	msgbufenabled;			/* is logging to the buffer enabled */
70struct	msgbuf *msgbufp;		/* the mapped buffer, itself. */
71
72void filt_logrdetach(struct knote *kn);
73int filt_logread(struct knote *kn, long hint);
74
75struct filterops logread_filtops =
76	{ 1, NULL, filt_logrdetach, filt_logread};
77
78void
79initmsgbuf(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*/
112int
113logopen(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*/
125int
126logclose(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*/
138int
139logread(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*/
185int
186logselect(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
207int
208logkqfilter(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
231void
232filt_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
240int
241filt_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
250void
251logwakeup()
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*/
267int
268logioctl(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