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