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