1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Edward Sze-Tyan Wang. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93"; 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/time.h> 44 #include <sys/mman.h> 45 46 #include <limits.h> 47 #include <fcntl.h> 48 #include <errno.h> 49 #include <unistd.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <err.h> 54 #include "extern.h" 55 56 static void rlines __P((FILE *, long, struct stat *)); 57 58 /* 59 * forward -- display the file, from an offset, forward. 60 * 61 * There are eight separate cases for this -- regular and non-regular 62 * files, by bytes or lines and from the beginning or end of the file. 63 * 64 * FBYTES byte offset from the beginning of the file 65 * REG seek 66 * NOREG read, counting bytes 67 * 68 * FLINES line offset from the beginning of the file 69 * REG read, counting lines 70 * NOREG read, counting lines 71 * 72 * RBYTES byte offset from the end of the file 73 * REG seek 74 * NOREG cyclically read characters into a wrap-around buffer 75 * 76 * RLINES 77 * REG mmap the file and step back until reach the correct offset. 78 * NOREG cyclically read lines into a wrap-around array of buffers 79 */ 80 void 81 forward(fp, style, off, sbp) 82 FILE *fp; 83 enum STYLE style; 84 long off; 85 struct stat *sbp; 86 { 87 register int ch; 88 struct timeval interval; 89 struct stat sb2; 90 91 switch(style) { 92 case FBYTES: 93 if (off == 0) 94 break; 95 if (S_ISREG(sbp->st_mode)) { 96 if (sbp->st_size < off) 97 off = sbp->st_size; 98 if (fseek(fp, off, SEEK_SET) == -1) { 99 ierr(); 100 return; 101 } 102 } else while (off--) 103 if ((ch = getc(fp)) == EOF) { 104 if (ferror(fp)) { 105 ierr(); 106 return; 107 } 108 break; 109 } 110 break; 111 case FLINES: 112 if (off == 0) 113 break; 114 for (;;) { 115 if ((ch = getc(fp)) == EOF) { 116 if (ferror(fp)) { 117 ierr(); 118 return; 119 } 120 break; 121 } 122 if (ch == '\n' && !--off) 123 break; 124 } 125 break; 126 case RBYTES: 127 if (S_ISREG(sbp->st_mode)) { 128 if (sbp->st_size >= off && 129 fseek(fp, -off, SEEK_END) == -1) { 130 ierr(); 131 return; 132 } 133 } else if (off == 0) { 134 while (getc(fp) != EOF); 135 if (ferror(fp)) { 136 ierr(); 137 return; 138 } 139 } else 140 if (bytes(fp, off)) 141 return; 142 break; 143 case RLINES: 144 if (S_ISREG(sbp->st_mode)) 145 if (!off) { 146 if (fseek(fp, 0L, SEEK_END) == -1) { 147 ierr(); 148 return; 149 } 150 } else 151 rlines(fp, off, sbp); 152 else if (off == 0) { 153 while (getc(fp) != EOF); 154 if (ferror(fp)) { 155 ierr(); 156 return; 157 } 158 } else 159 if (lines(fp, off)) 160 return; 161 break; 162 } 163 164 /* 165 * We pause for 1/4 second after displaying any data that has 166 * accumulated since we read the file. 167 */ 168 169 for (;;) { 170 while ((ch = getc(fp)) != EOF) 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; 180 181 (void) usleep(250000); 182 clearerr(fp); 183 184 if (Fflag && fileno(fp) != STDIN_FILENO && 185 stat(fname, &sb2) != -1) { 186 if (sb2.st_ino != sbp->st_ino || 187 sb2.st_dev != sbp->st_dev || 188 sb2.st_rdev != sbp->st_rdev || 189 sb2.st_nlink == 0) { 190 fp = freopen(fname, "r", fp); 191 if (fp == NULL) { 192 ierr(); 193 break; 194 } 195 *sbp = sb2; 196 } 197 } 198 } 199 } 200 201 /* 202 * rlines -- display the last offset lines of the file. 203 */ 204 static void 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)) 215 return; 216 217 if (size > SIZE_T_MAX) { 218 errno = EFBIG; 219 ierr(); 220 return; 221 } 222 223 if ((start = mmap(NULL, (size_t)size, 224 PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) { 225 ierr(); 226 return; 227 } 228 229 /* Last char is special, ignore whether newline or not. */ 230 for (p = start + size - 1; --size;) 231 if (*--p == '\n' && !--off) { 232 ++p; 233 break; 234 } 235 236 /* Set the file pointer to reflect the length displayed. */ 237 size = sbp->st_size - size; 238 WR(p, size); 239 if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) { 240 ierr(); 241 return; 242 } 243 if (munmap(start, (size_t)sbp->st_size)) { 244 ierr(); 245 return; 246 } 247 } 248