Annotation of src/usr.bin/tail/forward.c, Revision 1.20
1.20 ! otto 1: /* $OpenBSD: forward.c,v 1.19 2004/03/01 16:35:05 otto Exp $ */
1.2 niklas 2: /* $NetBSD: forward.c,v 1.7 1996/02/13 16:49:10 ghudson Exp $ */
1.1 deraadt 3:
4: /*-
5: * Copyright (c) 1991, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Edward Sze-Tyan Wang.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
1.15 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: #if 0
38: static char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93";
39: #endif
1.20 ! otto 40: static char rcsid[] = "$OpenBSD: forward.c,v 1.19 2004/03/01 16:35:05 otto Exp $";
1.1 deraadt 41: #endif /* not lint */
42:
43: #include <sys/types.h>
44: #include <sys/stat.h>
45: #include <sys/mman.h>
1.12 art 46: #include <sys/event.h>
1.1 deraadt 47:
1.4 millert 48: #include <err.h>
49: #include <errno.h>
50: #include <fcntl.h>
1.1 deraadt 51: #include <limits.h>
52: #include <stdio.h>
53: #include <stdlib.h>
54: #include <string.h>
1.4 millert 55: #include <unistd.h>
56:
1.1 deraadt 57: #include "extern.h"
58:
1.18 otto 59: static int rlines(FILE *, off_t, struct stat *);
1.1 deraadt 60:
61: /*
62: * forward -- display the file, from an offset, forward.
63: *
64: * There are eight separate cases for this -- regular and non-regular
65: * files, by bytes or lines and from the beginning or end of the file.
66: *
67: * FBYTES byte offset from the beginning of the file
68: * REG seek
69: * NOREG read, counting bytes
70: *
71: * FLINES line offset from the beginning of the file
72: * REG read, counting lines
73: * NOREG read, counting lines
74: *
75: * RBYTES byte offset from the end of the file
76: * REG seek
77: * NOREG cyclically read characters into a wrap-around buffer
78: *
79: * RLINES
1.16 henning 80: * REG step back until the correct offset is reached.
1.1 deraadt 81: * NOREG cyclically read lines into a wrap-around array of buffers
82: */
83: void
84: forward(fp, style, off, sbp)
85: FILE *fp;
86: enum STYLE style;
1.18 otto 87: off_t off;
1.1 deraadt 88: struct stat *sbp;
89: {
1.12 art 90: int ch;
1.6 millert 91: struct stat nsb;
1.20 ! otto 92: int kq, queue;
1.12 art 93: struct kevent ke;
1.1 deraadt 94:
95: switch(style) {
96: case FBYTES:
97: if (off == 0)
98: break;
99: if (S_ISREG(sbp->st_mode)) {
100: if (sbp->st_size < off)
101: off = sbp->st_size;
1.18 otto 102: if (fseeko(fp, off, SEEK_SET) == -1) {
1.1 deraadt 103: ierr();
104: return;
105: }
106: } else while (off--)
107: if ((ch = getc(fp)) == EOF) {
108: if (ferror(fp)) {
109: ierr();
110: return;
111: }
112: break;
113: }
114: break;
115: case FLINES:
116: if (off == 0)
117: break;
118: for (;;) {
119: if ((ch = getc(fp)) == EOF) {
120: if (ferror(fp)) {
121: ierr();
122: return;
123: }
124: break;
125: }
126: if (ch == '\n' && !--off)
127: break;
128: }
129: break;
130: case RBYTES:
131: if (S_ISREG(sbp->st_mode)) {
132: if (sbp->st_size >= off &&
1.18 otto 133: fseeko(fp, -off, SEEK_END) == -1) {
1.1 deraadt 134: ierr();
135: return;
136: }
137: } else if (off == 0) {
1.7 millert 138: while (getc(fp) != EOF)
139: ;
1.1 deraadt 140: if (ferror(fp)) {
141: ierr();
142: return;
143: }
1.9 ericj 144: } else {
145: if (bytes(fp, off))
146: return;
147: }
1.1 deraadt 148: break;
149: case RLINES:
1.7 millert 150: if (S_ISREG(sbp->st_mode)) {
1.1 deraadt 151: if (!off) {
1.18 otto 152: if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
1.1 deraadt 153: ierr();
154: return;
155: }
1.7 millert 156: } else if (rlines(fp, off, sbp) != 0)
157: lines(fp, off);
158: } else if (off == 0) {
159: while (getc(fp) != EOF)
160: ;
1.1 deraadt 161: if (ferror(fp)) {
162: ierr();
163: return;
164: }
1.9 ericj 165: } else {
166: if (lines(fp, off))
167: return;
168: }
1.1 deraadt 169: break;
170: }
171:
1.12 art 172: kq = -1;
173: kq_retry:
174: if (fflag && ((kq = kqueue()) >= 0)) {
175: ke.ident = fileno(fp);
176: ke.flags = EV_ENABLE|EV_ADD|EV_CLEAR;
177: ke.filter = EVFILT_READ;
178: ke.fflags = ke.data = 0;
179: ke.udata = NULL;
180: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
181: close(kq);
182: kq = -1;
183: } else if (S_ISREG(sbp->st_mode)) {
184: ke.ident = fileno(fp);
185: ke.flags = EV_ENABLE|EV_ADD|EV_CLEAR;
186: ke.filter = EVFILT_VNODE;
1.19 otto 187: ke.fflags = NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE;
1.12 art 188: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
189: close(kq);
190: kq = -1;
191: }
192: }
193: }
194:
1.1 deraadt 195: for (;;) {
1.6 millert 196: while (!feof(fp) && (ch = getc(fp)) != EOF)
1.1 deraadt 197: if (putchar(ch) == EOF)
198: oerr();
199: if (ferror(fp)) {
200: ierr();
1.12 art 201: if (kq != -1)
202: close(kq);
1.1 deraadt 203: return;
204: }
205: (void)fflush(stdout);
206: if (!fflag)
207: break;
208: clearerr(fp);
1.20 ! otto 209: queue = 1;
1.12 art 210: if (kq < 0 || kevent(kq, NULL, 0, &ke, 1, NULL) <= 0) {
1.20 ! otto 211: queue = 0;
1.12 art 212: sleep(1);
213: } else if (ke.filter == EVFILT_READ) {
214: continue;
1.19 otto 215: } else if ((ke.fflags & NOTE_TRUNCATE) == 0) {
1.12 art 216: /*
217: * File was renamed or deleted.
218: *
219: * Continue to look at it until a new file reappears
220: * with the same name.
221: * Fall back to the old algorithm for that.
222: */
223: close(kq);
224: kq = -1;
225: }
1.6 millert 226:
1.11 art 227: if (is_stdin || stat(fname, &nsb) != 0)
1.6 millert 228: continue;
229: /* Reopen file if the inode changes or file was truncated */
230: if (nsb.st_ino != sbp->st_ino) {
231: warnx("%s has been replaced, reopening.", fname);
232: if ((fp = freopen(fname, "r", fp)) == NULL) {
233: ierr();
1.12 art 234: if (kq >= 0)
235: close(kq);
1.6 millert 236: return;
237: }
238: (void)memcpy(sbp, &nsb, sizeof(nsb));
1.12 art 239: goto kq_retry;
1.20 ! otto 240: } else if ((queue && (ke.fflags & NOTE_TRUNCATE)) ||
! 241: (!queue && nsb.st_size < sbp->st_size)) {
1.6 millert 242: warnx("%s has been truncated, resetting.", fname);
1.19 otto 243: fpurge(fp);
1.6 millert 244: rewind(fp);
245: }
1.19 otto 246: (void)memcpy(sbp, &nsb, sizeof(nsb));
1.1 deraadt 247: }
1.12 art 248: if (kq >= 0)
249: close(kq);
1.1 deraadt 250: }
251:
252: /*
253: * rlines -- display the last offset lines of the file.
254: */
1.7 millert 255: static int
1.18 otto 256: rlines(FILE *fp, off_t off, struct stat *sbp)
1.1 deraadt 257: {
1.16 henning 258: off_t pos;
259: int ch;
1.1 deraadt 260:
1.16 henning 261: pos = sbp->st_size;
262: if (pos == 0)
1.7 millert 263: return (0);
1.1 deraadt 264:
1.16 henning 265: /*
266: * Position before char.
1.17 otto 267: * Last char is special, ignore it whether newline or not.
1.16 henning 268: */
269: pos -= 2;
270: ch = EOF;
271: for (; off > 0 && pos >= 0; pos--) {
272: /* A seek per char isn't a problem with a smart stdio */
273: if (fseeko(fp, pos, SEEK_SET) == -1) {
274: ierr();
275: return (1);
276: }
277: if ((ch = getc(fp)) == '\n')
278: off--;
279: else if (ch == EOF) {
280: if (ferror(fp)) {
281: ierr();
282: return (1);
283: }
1.1 deraadt 284: break;
285: }
1.16 henning 286: }
287: /* If we read until start of file, put back last read char */
288: if (pos < 0 && off > 0 && ch != EOF && ungetc(ch, fp) == EOF) {
1.1 deraadt 289: ierr();
1.7 millert 290: return (1);
1.1 deraadt 291: }
1.16 henning 292:
293: while (!feof(fp) && (ch = getc(fp)) != EOF)
294: if (putchar(ch) == EOF)
295: oerr();
296: if (ferror(fp)) {
1.7 millert 297: ierr();
298: return (1);
1.1 deraadt 299: }
1.7 millert 300:
301: return (0);
1.1 deraadt 302: }