Annotation of src/usr.bin/tail/forward.c, Revision 1.6
1.6 ! millert 1: /* $OpenBSD: forward.c,v 1.5 1997/05/29 14:57:31 kstailey 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.6 ! millert 44: static char rcsid[] = "$OpenBSD: forward.c,v 1.5 1997/05/29 14:57:31 kstailey Exp $";
1.1 deraadt 45: #endif /* not lint */
46:
47: #include <sys/types.h>
48: #include <sys/stat.h>
49: #include <sys/mman.h>
50:
1.4 millert 51: #include <err.h>
52: #include <errno.h>
53: #include <fcntl.h>
1.1 deraadt 54: #include <limits.h>
55: #include <stdio.h>
56: #include <stdlib.h>
57: #include <string.h>
1.4 millert 58: #include <unistd.h>
59:
1.1 deraadt 60: #include "extern.h"
61:
62: static void rlines __P((FILE *, long, struct stat *));
63:
64: /*
65: * forward -- display the file, from an offset, forward.
66: *
67: * There are eight separate cases for this -- regular and non-regular
68: * files, by bytes or lines and from the beginning or end of the file.
69: *
70: * FBYTES byte offset from the beginning of the file
71: * REG seek
72: * NOREG read, counting bytes
73: *
74: * FLINES line offset from the beginning of the file
75: * REG read, counting lines
76: * NOREG read, counting lines
77: *
78: * RBYTES byte offset from the end of the file
79: * REG seek
80: * NOREG cyclically read characters into a wrap-around buffer
81: *
82: * RLINES
83: * REG mmap the file and step back until reach the correct offset.
84: * NOREG cyclically read lines into a wrap-around array of buffers
85: */
86: void
87: forward(fp, style, off, sbp)
88: FILE *fp;
89: enum STYLE style;
90: long off;
91: struct stat *sbp;
92: {
93: register int ch;
1.6 ! millert 94: struct stat nsb;
1.1 deraadt 95:
96: switch(style) {
97: case FBYTES:
98: if (off == 0)
99: break;
100: if (S_ISREG(sbp->st_mode)) {
101: if (sbp->st_size < off)
102: off = sbp->st_size;
103: if (fseek(fp, off, SEEK_SET) == -1) {
104: ierr();
105: return;
106: }
107: } else while (off--)
108: if ((ch = getc(fp)) == EOF) {
109: if (ferror(fp)) {
110: ierr();
111: return;
112: }
113: break;
114: }
115: break;
116: case FLINES:
117: if (off == 0)
118: break;
119: for (;;) {
120: if ((ch = getc(fp)) == EOF) {
121: if (ferror(fp)) {
122: ierr();
123: return;
124: }
125: break;
126: }
127: if (ch == '\n' && !--off)
128: break;
129: }
130: break;
131: case RBYTES:
132: if (S_ISREG(sbp->st_mode)) {
133: if (sbp->st_size >= off &&
134: fseek(fp, -off, SEEK_END) == -1) {
135: ierr();
136: return;
137: }
138: } else if (off == 0) {
139: while (getc(fp) != EOF);
140: if (ferror(fp)) {
141: ierr();
142: return;
143: }
144: } else
145: bytes(fp, off);
146: break;
147: case RLINES:
148: if (S_ISREG(sbp->st_mode))
149: if (!off) {
150: if (fseek(fp, 0L, SEEK_END) == -1) {
151: ierr();
152: return;
153: }
154: } else
155: rlines(fp, off, sbp);
156: else if (off == 0) {
157: while (getc(fp) != EOF);
158: if (ferror(fp)) {
159: ierr();
160: return;
161: }
162: } else
163: lines(fp, off);
164: break;
165: }
166:
167: for (;;) {
1.6 ! millert 168: while (!feof(fp) && (ch = getc(fp)) != EOF)
1.1 deraadt 169: if (putchar(ch) == EOF)
170: oerr();
171: if (ferror(fp)) {
172: ierr();
173: return;
174: }
175: (void)fflush(stdout);
176: if (!fflag)
177: break;
1.5 kstailey 178: sleep(1);
1.1 deraadt 179: clearerr(fp);
1.6 ! millert 180:
! 181: if (stat(fname, &nsb) != 0)
! 182: continue;
! 183: /* Reopen file if the inode changes or file was truncated */
! 184: if (nsb.st_ino != sbp->st_ino) {
! 185: warnx("%s has been replaced, reopening.", fname);
! 186: if ((fp = freopen(fname, "r", fp)) == NULL) {
! 187: ierr();
! 188: return;
! 189: }
! 190: (void)memcpy(sbp, &nsb, sizeof(nsb));
! 191: } else if (nsb.st_size < sbp->st_size) {
! 192: warnx("%s has been truncated, resetting.", fname);
! 193: rewind(fp);
! 194: (void)memcpy(sbp, &nsb, sizeof(nsb));
! 195: }
1.1 deraadt 196: }
197: }
198:
199: /*
200: * rlines -- display the last offset lines of the file.
201: */
202: static void
203: rlines(fp, off, sbp)
204: FILE *fp;
205: long off;
206: struct stat *sbp;
207: {
208: register off_t size;
209: register char *p;
210: char *start;
211:
212: if (!(size = sbp->st_size))
213: return;
214:
215: if (size > SIZE_T_MAX) {
1.4 millert 216: errx(0, "%s: %s", fname, strerror(EFBIG));
1.1 deraadt 217: return;
218: }
219:
220: if ((start = mmap(NULL, (size_t)size,
221: PROT_READ, 0, fileno(fp), (off_t)0)) == (caddr_t)-1) {
1.4 millert 222: errx(0, "%s: %s", fname, strerror(EFBIG));
1.1 deraadt 223: return;
224: }
225:
226: /* Last char is special, ignore whether newline or not. */
227: for (p = start + size - 1; --size;)
228: if (*--p == '\n' && !--off) {
229: ++p;
230: break;
231: }
232:
233: /* Set the file pointer to reflect the length displayed. */
234: size = sbp->st_size - size;
235: WR(p, size);
236: if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) {
237: ierr();
238: return;
239: }
240: if (munmap(start, (size_t)sbp->st_size)) {
1.4 millert 241: err(0, fname);
1.1 deraadt 242: return;
243: }
244: }