1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)subr_log.c 2.1 (2.11BSD) 1999/4/29
7: */
8:
9: /*
10: * logioctl() had the wrong number of arguments. Argh! Apparently this
11: * driver was overlooked when 'dev' was added to ioctl entry points.
12: *
13: * logclose() returned garbage. this went unnoticed because most programs
14: * don't check status when doing a close.
15:
16: * Remove vax ifdefs - this driver is never going back to vaxland.
17: *
18: * Add support for multiple log devices. Minor device 0 is the traditional
19: * kernel logger (/dev/klog), minor device 1 is reserved for the future device
20: * error logging daemon. Minor device 2 is used by the 'accounting' daemon
21: * 'acctd'.
22: */
23:
24: #define NLOG 3
25: int nlog = NLOG;
26:
27: #include "param.h"
28: #include "user.h"
29: #include "proc.h"
30: #include "ioctl.h"
31: #include "msgbuf.h"
32: #include "file.h"
33: #include "inode.h"
34: #include "errno.h"
35: #include "uio.h"
36: #include "machine/seg.h"
37: #include "map.h"
38:
39: #define LOG_RDPRI (PZERO + 1)
40:
41: #define LOG_OPEN 0x01
42: #define LOG_ASYNC 0x04
43: #define LOG_RDWAIT 0x08
44:
45: /*
46: * This is an efficiency hack. This global is provided for exit() to
47: * test and avoid the overhead of function calls when accounting is
48: * turned off.
49: */
50: int Acctopen;
51:
52: struct msgbuf msgbuf[NLOG];
53: static struct logsoftc
54: {
55: int sc_state; /* see above for possibilities */
56: struct proc *sc_selp; /* process waiting on select call */
57: int sc_pgid; /* process/group for async I/O */
58: int sc_overrun; /* full buffer count */
59: } logsoftc[NLOG];
60:
61: /*ARGSUSED*/
62: logopen(dev, mode)
63: dev_t dev;
64: int mode;
65: {
66: register int unit = minor(dev);
67:
68: if (unit >= NLOG)
69: return(ENODEV);
70: if (logisopen(unit))
71: return(EBUSY);
72: if (msgbuf[unit].msg_click == 0) /* no buffer allocated */
73: return(ENOMEM);
74: logsoftc[unit].sc_state |= LOG_OPEN;
75: if (unit == logACCT)
76: Acctopen = 1;
77: logsoftc[unit].sc_pgid = u.u_procp->p_pid; /* signal process only */
78: logsoftc[unit].sc_overrun = 0;
79: return(0);
80: }
81:
82: /*ARGSUSED*/
83: logclose(dev, flag)
84: dev_t dev;
85: int flag;
86: {
87: register int unit = minor(dev);
88:
89: logsoftc[unit].sc_state = 0;
90: if (unit == logACCT)
91: Acctopen = 0;
92: return(0);
93: }
94:
95: /*
96: * This is a helper function to keep knowledge of this driver's data
97: * structures away from the rest of the kernel.
98: */
99: logisopen(unit)
100: int unit;
101: {
102:
103: if (logsoftc[unit].sc_state & LOG_OPEN)
104: return(1);
105: return(0);
106: }
107:
108: /*ARGSUSED*/
109: logread(dev, uio, flag)
110: dev_t dev;
111: struct uio *uio;
112: int flag;
113: {
114: register int l;
115: register struct logsoftc *lp;
116: register struct msgbuf *mp;
117: int s, error = 0;
118: char buf[ctob(2)];
119:
120: l = minor(dev);
121: lp = &logsoftc[l];
122: mp = &msgbuf[l];
123: s = splhigh();
124: while (mp->msg_bufr == mp->msg_bufx)
125: {
126: if (flag & IO_NDELAY)
127: {
128: splx(s);
129: return(EWOULDBLOCK);
130: }
131: lp->sc_state |= LOG_RDWAIT;
132: sleep((caddr_t)mp, LOG_RDPRI);
133: }
134: lp->sc_state &= ~LOG_RDWAIT;
135:
136: while (uio->uio_resid)
137: {
138: l = mp->msg_bufx - mp->msg_bufr;
139: /*
140: * If the reader and writer are equal then we have caught up and there
141: * is nothing more to transfer.
142: */
143: if (l == 0)
144: break;
145: /*
146: * If the write pointer is behind the reader then only consider as
147: * available for now the bytes from the read pointer thru the end of
148: * the buffer.
149: */
150: if (l < 0)
151: {
152: l = MSG_BSIZE - mp->msg_bufr;
153: /*
154: * If the reader is exactly at the end of the buffer it is
155: * time to wrap it around to the beginning and recalculate the
156: * amount of data to transfer.
157: */
158: if (l == 0)
159: {
160: mp->msg_bufr = 0;
161: continue;
162: }
163: }
164: l = MIN(l, uio->uio_resid);
165: l = MIN(l, sizeof buf);
166: mapseg5(mp->msg_click, (btoc(MSG_BSIZE) << 8) | RW);
167: bcopy(&mp->msg_bufc[mp->msg_bufr], buf, l);
168: normalseg5();
169: error = uiomove(buf, l, uio);
170: if (error)
171: break;
172: mp->msg_bufr += l;
173: }
174: splx(s);
175: return(error);
176: }
177:
178: /*ARGSUSED*/
179: logselect(dev, rw)
180: dev_t dev;
181: int rw;
182: {
183: register int s = splhigh();
184: int unit = minor(dev);
185:
186: switch (rw)
187: {
188: case FREAD:
189: if (msgbuf[unit].msg_bufr != msgbuf[unit].msg_bufx)
190: {
191: splx(s);
192: return(1);
193: }
194: logsoftc[unit].sc_selp = u.u_procp;
195: break;
196: }
197: splx(s);
198: return(0);
199: }
200:
201: logwakeup(unit)
202: int unit;
203: {
204: register struct proc *p;
205: register struct logsoftc *lp;
206: register struct msgbuf *mp;
207:
208: if (!logisopen(unit))
209: return;
210: lp = &logsoftc[unit];
211: mp = &msgbuf[unit];
212: if (lp->sc_selp)
213: {
214: selwakeup(lp->sc_selp, (long) 0);
215: lp->sc_selp = 0;
216: }
217: if (lp->sc_state & LOG_ASYNC && (mp->msg_bufx != mp->msg_bufr))
218: {
219: if (lp->sc_pgid < 0)
220: gsignal(-lp->sc_pgid, SIGIO);
221: else if (p = pfind(lp->sc_pgid))
222: psignal(p, SIGIO);
223: }
224: if (lp->sc_state & LOG_RDWAIT)
225: {
226: wakeup((caddr_t)mp);
227: lp->sc_state &= ~LOG_RDWAIT;
228: }
229: }
230:
231: /*ARGSUSED*/
232: logioctl(dev, com, data, flag)
233: dev_t dev;
234: u_int com;
235: caddr_t data;
236: int flag;
237: {
238: long l;
239: register int s;
240: int unit;
241: register struct logsoftc *lp;
242: register struct msgbuf *mp;
243:
244: unit = minor(dev);
245: lp = &logsoftc[unit];
246: mp = &msgbuf[unit];
247:
248: switch (com)
249: {
250: case FIONREAD:
251: s = splhigh();
252: l = mp->msg_bufx - mp->msg_bufr;
253: splx(s);
254: if (l < 0)
255: l += MSG_BSIZE;
256: *(off_t *)data = l;
257: break;
258: case FIONBIO:
259: break;
260: case FIOASYNC:
261: if (*(int *)data)
262: lp->sc_state |= LOG_ASYNC;
263: else
264: lp->sc_state &= ~LOG_ASYNC;
265: break;
266: case TIOCSPGRP:
267: lp->sc_pgid = *(int *)data;
268: break;
269: case TIOCGPGRP:
270: *(int *)data = lp->sc_pgid;
271: break;
272: default:
273: return(-1);
274: }
275: return(0);
276: }
277:
278: /*
279: * This is inefficient for single character writes. Alas, changing this
280: * to be buffered would affect the networking code's use of printf.
281: */
282:
283: logwrt(buf,len,log)
284: char *buf;
285: int len;
286: int log;
287: {
288: segm s5;
289: register struct msgbuf *mp = &msgbuf[log];
290: struct logsoftc *lp = &logsoftc[log];
291: register int infront;
292: int s, n, writer, err = 0;
293:
294: if (mp->msg_magic != MSG_MAGIC || (len > MSG_BSIZE))
295: return(-1);
296: saveseg5(s5);
297: /*
298: * Hate to do this but since this can be called from anywhere in the kernel
299: * we have to hold off any interrupt service routines so they don't change
300: * things. This looks like a lot of code but it isn't really.
301: */
302: s = splhigh();
303: while (len)
304: {
305: again: infront = MSG_BSIZE - mp->msg_bufx;
306: if (infront <= 0)
307: {
308: mp->msg_bufx = 0;
309: infront = MSG_BSIZE - mp->msg_bufr;
310: }
311: n = mp->msg_bufr - mp->msg_bufx;
312: if (n < 0) /* bufr < bufx */
313: writer = (MSG_BSIZE - mp->msg_bufx) + mp->msg_bufr;
314: else if (n == 0)
315: writer = MSG_BSIZE;
316: else
317: {
318: writer = n;
319: infront = n;
320: }
321: if (len > writer)
322: {
323: /*
324: * won't fit. the total number of bytes to be written is
325: * greater than the number available. the buffer is full.
326: * throw away the old data and keep the current data by resetting
327: * the 'writer' pointer to the current 'reader' position. Bump the
328: * overrun counter in case anyone wants to look at it for debugging.
329: */
330: lp->sc_overrun++;
331: mp->msg_bufx = mp->msg_bufr;
332: goto again;
333: }
334: if (infront > len)
335: infront = len;
336: mapseg5(mp->msg_click, (btoc(MSG_BSIZE) << 8) | RW); /* XXX */
337: bcopy(buf, &mp->msg_bufc[mp->msg_bufx], infront);
338: restorseg5(s5);
339: mp->msg_bufx += infront;
340: len -= infront;
341: buf += infront;
342: }
343: out: splx(s);
344: return(err);
345: }
346:
347: /*
348: * Initialize the log driver. Called from the system startup code (machdep2.c).
349: * All buffers are the same (MSG_BSIZE) size.
350: */
351:
352: loginit()
353: {
354: register struct msgbuf *mp;
355:
356: for (mp = &msgbuf[0]; mp < &msgbuf[NLOG]; mp++)
357: {
358: mp->msg_click = malloc(coremap,btoc(MSG_BSIZE));
359: if (!mp->msg_click)
360: return(-1);
361: mp->msg_magic = MSG_MAGIC;
362: mp->msg_bufc = SEG5;
363: mp->msg_bufx = mp->msg_bufr = 0;
364: }
365: return(0);
366: }
Defined functions
Defined variables
nlog
defined in line
25;
never used
Defined struct's
Defined macros
NLOG
defined in line
24; used 5 times