Annotation of src/usr.bin/tail/forward.c, Revision 1.26
1.26 ! deraadt 1: /* $OpenBSD: forward.c,v 1.25 2008/11/13 18:33:03 landry 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: #include <sys/types.h>
37: #include <sys/stat.h>
1.12 art 38: #include <sys/event.h>
1.1 deraadt 39:
1.4 millert 40: #include <err.h>
1.1 deraadt 41: #include <stdio.h>
42: #include <string.h>
1.4 millert 43: #include <unistd.h>
44:
1.1 deraadt 45: #include "extern.h"
46:
1.18 otto 47: static int rlines(FILE *, off_t, struct stat *);
1.1 deraadt 48:
49: /*
50: * forward -- display the file, from an offset, forward.
51: *
52: * There are eight separate cases for this -- regular and non-regular
53: * files, by bytes or lines and from the beginning or end of the file.
54: *
55: * FBYTES byte offset from the beginning of the file
56: * REG seek
57: * NOREG read, counting bytes
58: *
59: * FLINES line offset from the beginning of the file
60: * REG read, counting lines
61: * NOREG read, counting lines
62: *
63: * RBYTES byte offset from the end of the file
64: * REG seek
65: * NOREG cyclically read characters into a wrap-around buffer
66: *
67: * RLINES
1.16 henning 68: * REG step back until the correct offset is reached.
1.1 deraadt 69: * NOREG cyclically read lines into a wrap-around array of buffers
70: */
71: void
1.21 kjell 72: forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
1.1 deraadt 73: {
1.12 art 74: int ch;
1.25 landry 75: struct stat nsb;
76: int kq, queue;
77: struct kevent ke;
1.1 deraadt 78:
79: switch(style) {
80: case FBYTES:
81: if (off == 0)
82: break;
83: if (S_ISREG(sbp->st_mode)) {
84: if (sbp->st_size < off)
85: off = sbp->st_size;
1.18 otto 86: if (fseeko(fp, off, SEEK_SET) == -1) {
1.1 deraadt 87: ierr();
88: return;
89: }
90: } else while (off--)
91: if ((ch = getc(fp)) == EOF) {
92: if (ferror(fp)) {
93: ierr();
94: return;
95: }
96: break;
97: }
98: break;
99: case FLINES:
100: if (off == 0)
101: break;
102: for (;;) {
103: if ((ch = getc(fp)) == EOF) {
104: if (ferror(fp)) {
105: ierr();
106: return;
107: }
108: break;
109: }
110: if (ch == '\n' && !--off)
111: break;
112: }
113: break;
114: case RBYTES:
115: if (S_ISREG(sbp->st_mode)) {
116: if (sbp->st_size >= off &&
1.18 otto 117: fseeko(fp, -off, SEEK_END) == -1) {
1.1 deraadt 118: ierr();
119: return;
120: }
121: } else if (off == 0) {
1.7 millert 122: while (getc(fp) != EOF)
123: ;
1.1 deraadt 124: if (ferror(fp)) {
125: ierr();
126: return;
127: }
1.9 ericj 128: } else {
129: if (bytes(fp, off))
130: return;
131: }
1.1 deraadt 132: break;
133: case RLINES:
1.7 millert 134: if (S_ISREG(sbp->st_mode)) {
1.1 deraadt 135: if (!off) {
1.18 otto 136: if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
1.1 deraadt 137: ierr();
138: return;
139: }
1.7 millert 140: } else if (rlines(fp, off, sbp) != 0)
141: lines(fp, off);
142: } else if (off == 0) {
143: while (getc(fp) != EOF)
144: ;
1.1 deraadt 145: if (ferror(fp)) {
146: ierr();
147: return;
148: }
1.9 ericj 149: } else {
150: if (lines(fp, off))
151: return;
152: }
1.1 deraadt 153: break;
154: }
155:
1.12 art 156: kq = -1;
1.25 landry 157: kq_retry:
158: if (fflag && ((kq = kqueue()) >= 0)) {
1.23 deraadt 159: EV_SET(&ke, fileno(fp), EVFILT_READ,
160: EV_ENABLE | EV_ADD | EV_CLEAR,
1.25 landry 161: 0,
162: 0, NULL);
163: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
164: close(kq);
165: kq = -1;
166: } else if (S_ISREG(sbp->st_mode)) {
1.23 deraadt 167: EV_SET(&ke, fileno(fp), EVFILT_VNODE,
168: EV_ENABLE | EV_ADD | EV_CLEAR,
169: NOTE_DELETE | NOTE_RENAME | NOTE_TRUNCATE,
170: 0, NULL);
1.25 landry 171: if (kevent(kq, &ke, 1, NULL, 0, NULL) < 0) {
172: close(kq);
173: kq = -1;
174: }
1.12 art 175: }
176: }
177:
1.1 deraadt 178: for (;;) {
1.6 millert 179: while (!feof(fp) && (ch = getc(fp)) != EOF)
1.1 deraadt 180: if (putchar(ch) == EOF)
181: oerr();
1.25 landry 182: if (ferror(fp)) {
183: ierr();
184: if (kq != -1)
185: close(kq);
186: return;
187: }
1.1 deraadt 188: (void)fflush(stdout);
1.25 landry 189: if (!fflag)
190: break;
1.1 deraadt 191: clearerr(fp);
1.25 landry 192: queue = 1;
193: if (kq < 0 || kevent(kq, NULL, 0, &ke, 1, NULL) <= 0) {
194: queue = 0;
1.12 art 195: sleep(1);
1.25 landry 196: } else if (ke.filter == EVFILT_READ) {
1.12 art 197: continue;
1.25 landry 198: } else if ((ke.fflags & NOTE_TRUNCATE) == 0) {
199: /*
200: * File was renamed or deleted.
201: *
202: * Continue to look at it until a new file reappears
203: * with the same name.
204: * Fall back to the old algorithm for that.
205: */
206: close(kq);
207: kq = -1;
208: }
1.24 landry 209:
1.25 landry 210: if (is_stdin || stat(fname, &nsb) != 0)
211: continue;
212: /* Reopen file if the inode changes or file was truncated */
213: if (nsb.st_ino != sbp->st_ino) {
214: warnx("%s has been replaced, reopening.", fname);
215: if ((fp = freopen(fname, "r", fp)) == NULL) {
216: ierr();
217: if (kq >= 0)
218: close(kq);
219: return;
1.6 millert 220: }
1.25 landry 221: (void)memcpy(sbp, &nsb, sizeof(nsb));
222: goto kq_retry;
223: } else if ((queue && (ke.fflags & NOTE_TRUNCATE)) ||
224: (!queue && nsb.st_size < sbp->st_size)) {
225: warnx("%s has been truncated, resetting.", fname);
226: fpurge(fp);
227: rewind(fp);
1.6 millert 228: }
1.25 landry 229: (void)memcpy(sbp, &nsb, sizeof(nsb));
1.1 deraadt 230: }
1.12 art 231: if (kq >= 0)
232: close(kq);
1.1 deraadt 233: }
234:
235: /*
236: * rlines -- display the last offset lines of the file.
237: */
1.7 millert 238: static int
1.18 otto 239: rlines(FILE *fp, off_t off, struct stat *sbp)
1.1 deraadt 240: {
1.16 henning 241: off_t pos;
242: int ch;
1.1 deraadt 243:
1.16 henning 244: pos = sbp->st_size;
245: if (pos == 0)
1.7 millert 246: return (0);
1.1 deraadt 247:
1.16 henning 248: /*
249: * Position before char.
1.17 otto 250: * Last char is special, ignore it whether newline or not.
1.16 henning 251: */
252: pos -= 2;
253: ch = EOF;
254: for (; off > 0 && pos >= 0; pos--) {
255: /* A seek per char isn't a problem with a smart stdio */
256: if (fseeko(fp, pos, SEEK_SET) == -1) {
257: ierr();
258: return (1);
259: }
260: if ((ch = getc(fp)) == '\n')
261: off--;
262: else if (ch == EOF) {
263: if (ferror(fp)) {
264: ierr();
265: return (1);
266: }
1.1 deraadt 267: break;
268: }
1.16 henning 269: }
270: /* If we read until start of file, put back last read char */
271: if (pos < 0 && off > 0 && ch != EOF && ungetc(ch, fp) == EOF) {
1.1 deraadt 272: ierr();
1.7 millert 273: return (1);
1.1 deraadt 274: }
1.16 henning 275:
276: while (!feof(fp) && (ch = getc(fp)) != EOF)
277: if (putchar(ch) == EOF)
278: oerr();
279: if (ferror(fp)) {
1.7 millert 280: ierr();
281: return (1);
1.1 deraadt 282: }
1.7 millert 283:
284: return (0);
1.1 deraadt 285: }