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