Annotation of src/usr.bin/tail/forward.c, Revision 1.11
1.11 ! art 1: /* $OpenBSD: forward.c,v 1.10 2000/10/12 10:18:38 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.11 ! art 44: static char rcsid[] = "$OpenBSD: forward.c,v 1.10 2000/10/12 10:18:38 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>
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:
1.7 millert 62: static int rlines __P((FILE *, long, struct stat *));
1.1 deraadt 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) {
1.7 millert 139: while (getc(fp) != EOF)
140: ;
1.1 deraadt 141: if (ferror(fp)) {
142: ierr();
143: return;
144: }
1.9 ericj 145: } else {
146: if (bytes(fp, off))
147: return;
148: }
1.1 deraadt 149: break;
150: case RLINES:
1.7 millert 151: if (S_ISREG(sbp->st_mode)) {
1.1 deraadt 152: if (!off) {
153: if (fseek(fp, 0L, SEEK_END) == -1) {
154: ierr();
155: return;
156: }
1.7 millert 157: } else if (rlines(fp, off, sbp) != 0)
158: lines(fp, off);
159: } else if (off == 0) {
160: while (getc(fp) != EOF)
161: ;
1.1 deraadt 162: if (ferror(fp)) {
163: ierr();
164: return;
165: }
1.9 ericj 166: } else {
167: if (lines(fp, off))
168: return;
169: }
1.1 deraadt 170: break;
171: }
172:
173: for (;;) {
1.6 millert 174: while (!feof(fp) && (ch = getc(fp)) != EOF)
1.1 deraadt 175: if (putchar(ch) == EOF)
176: oerr();
177: if (ferror(fp)) {
178: ierr();
179: return;
180: }
181: (void)fflush(stdout);
182: if (!fflag)
183: break;
1.5 kstailey 184: sleep(1);
1.1 deraadt 185: clearerr(fp);
1.6 millert 186:
1.11 ! art 187: if (is_stdin || stat(fname, &nsb) != 0)
1.6 millert 188: continue;
189: /* Reopen file if the inode changes or file was truncated */
190: if (nsb.st_ino != sbp->st_ino) {
191: warnx("%s has been replaced, reopening.", fname);
192: if ((fp = freopen(fname, "r", fp)) == NULL) {
193: ierr();
194: return;
195: }
196: (void)memcpy(sbp, &nsb, sizeof(nsb));
197: } else if (nsb.st_size < sbp->st_size) {
198: warnx("%s has been truncated, resetting.", fname);
199: rewind(fp);
200: (void)memcpy(sbp, &nsb, sizeof(nsb));
201: }
1.1 deraadt 202: }
203: }
204:
205: /*
206: * rlines -- display the last offset lines of the file.
207: */
1.7 millert 208: static int
1.1 deraadt 209: rlines(fp, off, sbp)
210: FILE *fp;
211: long off;
212: struct stat *sbp;
213: {
214: register off_t size;
215: register char *p;
216: char *start;
217:
218: if (!(size = sbp->st_size))
1.7 millert 219: return (0);
1.1 deraadt 220:
1.7 millert 221: if (size > SIZE_T_MAX)
222: return (1);
1.1 deraadt 223:
1.8 mickey 224: if ((start = mmap(NULL, (size_t)size, PROT_READ, MAP_PRIVATE,
1.10 art 225: fileno(fp), (off_t)0)) == MAP_FAILED)
1.7 millert 226: return (1);
1.1 deraadt 227:
228: /* Last char is special, ignore whether newline or not. */
229: for (p = start + size - 1; --size;)
230: if (*--p == '\n' && !--off) {
231: ++p;
232: break;
233: }
234:
235: /* Set the file pointer to reflect the length displayed. */
236: size = sbp->st_size - size;
237: WR(p, size);
238: if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) {
239: ierr();
1.7 millert 240: return (1);
1.1 deraadt 241: }
242: if (munmap(start, (size_t)sbp->st_size)) {
1.7 millert 243: ierr();
244: return (1);
1.1 deraadt 245: }
1.7 millert 246:
247: return (0);
1.1 deraadt 248: }