Annotation of src/usr.bin/tail/forward.c, Revision 1.21
1.21 ! kjell 1: /* $OpenBSD: forward.c,v 1.20 2004/03/12 19:40: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.21 ! kjell 40: static char rcsid[] = "$OpenBSD: forward.c,v 1.20 2004/03/12 19:40: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
1.21 ! kjell 84: forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
1.1 deraadt 85: {
1.12 art 86: int ch;
1.6 millert 87: struct stat nsb;
1.20 otto 88: int kq, queue;
1.12 art 89: struct kevent ke;
1.1 deraadt 90:
91: switch(style) {
92: case FBYTES:
93: if (off == 0)
94: break;
95: if (S_ISREG(sbp->st_mode)) {
96: if (sbp->st_size < off)
97: off = sbp->st_size;
1.18 otto 98: if (fseeko(fp, off, SEEK_SET) == -1) {
1.1 deraadt 99: ierr();
100: return;
101: }
102: } else while (off--)
103: if ((ch = getc(fp)) == EOF) {
104: if (ferror(fp)) {
105: ierr();
106: return;
107: }
108: break;
109: }
110: break;
111: case FLINES:
112: if (off == 0)
113: break;
114: for (;;) {
115: if ((ch = getc(fp)) == EOF) {
116: if (ferror(fp)) {
117: ierr();
118: return;
119: }
120: break;
121: }
122: if (ch == '\n' && !--off)
123: break;
124: }
125: break;
126: case RBYTES:
127: if (S_ISREG(sbp->st_mode)) {
128: if (sbp->st_size >= off &&
1.18 otto 129: fseeko(fp, -off, SEEK_END) == -1) {
1.1 deraadt 130: ierr();
131: return;
132: }
133: } else if (off == 0) {
1.7 millert 134: while (getc(fp) != EOF)
135: ;
1.1 deraadt 136: if (ferror(fp)) {
137: ierr();
138: return;
139: }
1.9 ericj 140: } else {
141: if (bytes(fp, off))
142: return;
143: }
1.1 deraadt 144: break;
145: case RLINES:
1.7 millert 146: if (S_ISREG(sbp->st_mode)) {
1.1 deraadt 147: if (!off) {
1.18 otto 148: if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
1.1 deraadt 149: ierr();
150: return;
151: }
1.7 millert 152: } else if (rlines(fp, off, sbp) != 0)
153: lines(fp, off);
154: } else if (off == 0) {
155: while (getc(fp) != EOF)
156: ;
1.1 deraadt 157: if (ferror(fp)) {
158: ierr();
159: return;
160: }
1.9 ericj 161: } else {
162: if (lines(fp, off))
163: return;
164: }
1.1 deraadt 165: break;
166: }
167:
1.12 art 168: kq = -1;
169: kq_retry:
170: if (fflag && ((kq = kqueue()) >= 0)) {
171: ke.ident = fileno(fp);
172: ke.flags = EV_ENABLE|EV_ADD|EV_CLEAR;
173: ke.filter = EVFILT_READ;
174: ke.fflags = ke.data = 0;
175: ke.udata = NULL;
176: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
177: close(kq);
178: kq = -1;
179: } else if (S_ISREG(sbp->st_mode)) {
180: ke.ident = fileno(fp);
181: ke.flags = EV_ENABLE|EV_ADD|EV_CLEAR;
182: ke.filter = EVFILT_VNODE;
1.19 otto 183: ke.fflags = NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE;
1.12 art 184: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
185: close(kq);
186: kq = -1;
187: }
188: }
189: }
190:
1.1 deraadt 191: for (;;) {
1.6 millert 192: while (!feof(fp) && (ch = getc(fp)) != EOF)
1.1 deraadt 193: if (putchar(ch) == EOF)
194: oerr();
195: if (ferror(fp)) {
196: ierr();
1.12 art 197: if (kq != -1)
198: close(kq);
1.1 deraadt 199: return;
200: }
201: (void)fflush(stdout);
202: if (!fflag)
203: break;
204: clearerr(fp);
1.20 otto 205: queue = 1;
1.12 art 206: if (kq < 0 || kevent(kq, NULL, 0, &ke, 1, NULL) <= 0) {
1.20 otto 207: queue = 0;
1.12 art 208: sleep(1);
209: } else if (ke.filter == EVFILT_READ) {
210: continue;
1.19 otto 211: } else if ((ke.fflags & NOTE_TRUNCATE) == 0) {
1.12 art 212: /*
213: * File was renamed or deleted.
214: *
215: * Continue to look at it until a new file reappears
216: * with the same name.
217: * Fall back to the old algorithm for that.
218: */
219: close(kq);
220: kq = -1;
221: }
1.6 millert 222:
1.11 art 223: if (is_stdin || stat(fname, &nsb) != 0)
1.6 millert 224: continue;
225: /* Reopen file if the inode changes or file was truncated */
226: if (nsb.st_ino != sbp->st_ino) {
227: warnx("%s has been replaced, reopening.", fname);
228: if ((fp = freopen(fname, "r", fp)) == NULL) {
229: ierr();
1.12 art 230: if (kq >= 0)
231: close(kq);
1.6 millert 232: return;
233: }
234: (void)memcpy(sbp, &nsb, sizeof(nsb));
1.12 art 235: goto kq_retry;
1.20 otto 236: } else if ((queue && (ke.fflags & NOTE_TRUNCATE)) ||
237: (!queue && nsb.st_size < sbp->st_size)) {
1.6 millert 238: warnx("%s has been truncated, resetting.", fname);
1.19 otto 239: fpurge(fp);
1.6 millert 240: rewind(fp);
241: }
1.19 otto 242: (void)memcpy(sbp, &nsb, sizeof(nsb));
1.1 deraadt 243: }
1.12 art 244: if (kq >= 0)
245: close(kq);
1.1 deraadt 246: }
247:
248: /*
249: * rlines -- display the last offset lines of the file.
250: */
1.7 millert 251: static int
1.18 otto 252: rlines(FILE *fp, off_t off, struct stat *sbp)
1.1 deraadt 253: {
1.16 henning 254: off_t pos;
255: int ch;
1.1 deraadt 256:
1.16 henning 257: pos = sbp->st_size;
258: if (pos == 0)
1.7 millert 259: return (0);
1.1 deraadt 260:
1.16 henning 261: /*
262: * Position before char.
1.17 otto 263: * Last char is special, ignore it whether newline or not.
1.16 henning 264: */
265: pos -= 2;
266: ch = EOF;
267: for (; off > 0 && pos >= 0; pos--) {
268: /* A seek per char isn't a problem with a smart stdio */
269: if (fseeko(fp, pos, SEEK_SET) == -1) {
270: ierr();
271: return (1);
272: }
273: if ((ch = getc(fp)) == '\n')
274: off--;
275: else if (ch == EOF) {
276: if (ferror(fp)) {
277: ierr();
278: return (1);
279: }
1.1 deraadt 280: break;
281: }
1.16 henning 282: }
283: /* If we read until start of file, put back last read char */
284: if (pos < 0 && off > 0 && ch != EOF && ungetc(ch, fp) == EOF) {
1.1 deraadt 285: ierr();
1.7 millert 286: return (1);
1.1 deraadt 287: }
1.16 henning 288:
289: while (!feof(fp) && (ch = getc(fp)) != EOF)
290: if (putchar(ch) == EOF)
291: oerr();
292: if (ferror(fp)) {
1.7 millert 293: ierr();
294: return (1);
1.1 deraadt 295: }
1.7 millert 296:
297: return (0);
1.1 deraadt 298: }