add munmap call
[unix-history] / usr / src / usr.bin / tail / forward.c
CommitLineData
48f06ece
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Edward Sze-Tyan Wang.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
7542cdf7 12static char sccsid[] = "@(#)forward.c 5.6 (Berkeley) %G%";
48f06ece
KB
13#endif /* not lint */
14
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/time.h>
18#include <sys/mman.h>
19#include <fcntl.h>
20#include <errno.h>
21#include <unistd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include "extern.h"
26
27static void rlines __P((FILE *, long, struct stat *));
28
29/*
30 * forward -- display the file, from an offset, forward.
31 *
32 * There are eight separate cases for this -- regular and non-regular
33 * files, by bytes or lines and from the beginning or end of the file.
34 *
35 * FBYTES byte offset from the beginning of the file
36 * REG seek
37 * NOREG read, counting bytes
38 *
39 * FLINES line offset from the beginning of the file
40 * REG read, counting lines
41 * NOREG read, counting lines
42 *
43 * RBYTES byte offset from the end of the file
44 * REG seek
45 * NOREG cyclically read characters into a wrap-around buffer
46 *
47 * RLINES
48 * REG mmap the file and step back until reach the correct offset.
49 * NOREG cyclically read lines into a wrap-around array of buffers
50 */
51void
52forward(fp, style, off, sbp)
53 FILE *fp;
54 enum STYLE style;
55 long off;
56 struct stat *sbp;
57{
58 register int ch;
59 struct timeval second;
60 fd_set zero;
61
62 switch(style) {
63 case FBYTES:
64 if (off == 0)
65 break;
66 if (S_ISREG(sbp->st_mode)) {
67 if (sbp->st_size < off)
68 off = sbp->st_size;
31919d23 69 if (fseek(fp, off, SEEK_SET) == -1) {
48f06ece 70 ierr();
31919d23
KB
71 return;
72 }
48f06ece
KB
73 } else while (off--)
74 if ((ch = getc(fp)) == EOF) {
31919d23 75 if (ferror(fp)) {
48f06ece 76 ierr();
31919d23 77 return;
48f06ece 78 }
31919d23
KB
79 break;
80 }
48f06ece
KB
81 break;
82 case FLINES:
83 if (off == 0)
84 break;
85 for (;;) {
86 if ((ch = getc(fp)) == EOF) {
31919d23 87 if (ferror(fp)) {
48f06ece 88 ierr();
31919d23
KB
89 return;
90 }
48f06ece
KB
91 break;
92 }
93 if (ch == '\n' && !--off)
94 break;
95 }
96 break;
97 case RBYTES:
98 if (S_ISREG(sbp->st_mode)) {
99 if (sbp->st_size >= off &&
31919d23 100 fseek(fp, -off, SEEK_END) == -1) {
48f06ece 101 ierr();
31919d23
KB
102 return;
103 }
48f06ece
KB
104 } else if (off == 0) {
105 while (getc(fp) != EOF);
31919d23 106 if (ferror(fp)) {
48f06ece 107 ierr();
31919d23
KB
108 return;
109 }
48f06ece
KB
110 } else
111 bytes(fp, off);
112 break;
113 case RLINES:
114 if (S_ISREG(sbp->st_mode))
115 if (!off) {
31919d23 116 if (fseek(fp, 0L, SEEK_END) == -1) {
48f06ece 117 ierr();
31919d23
KB
118 return;
119 }
48f06ece
KB
120 } else
121 rlines(fp, off, sbp);
122 else if (off == 0) {
123 while (getc(fp) != EOF);
31919d23 124 if (ferror(fp)) {
48f06ece 125 ierr();
31919d23
KB
126 return;
127 }
48f06ece
KB
128 } else
129 lines(fp, off);
130 break;
131 }
132
133 /*
134 * We pause for one second after displaying any data that has
135 * accumulated since we read the file.
136 */
137 if (fflag) {
138 FD_ZERO(&zero);
139 second.tv_sec = 1;
140 second.tv_usec = 0;
141 }
142
143 for (;;) {
144 while ((ch = getc(fp)) != EOF)
145 if (putchar(ch) == EOF)
146 oerr();
31919d23 147 if (ferror(fp)) {
48f06ece 148 ierr();
31919d23
KB
149 return;
150 }
96cc7d48 151 (void)fflush(stdout);
48f06ece
KB
152 if (!fflag)
153 break;
154 /* Sleep(3) is eight system calls. Do it fast. */
155 if (select(0, &zero, &zero, &zero, &second) == -1)
31919d23 156 err(1, "select: %s", strerror(errno));
48f06ece
KB
157 clearerr(fp);
158 }
159}
160
161/*
162 * rlines -- display the last offset lines of the file.
163 */
164static void
165rlines(fp, off, sbp)
166 FILE *fp;
167 long off;
168 struct stat *sbp;
169{
170 register off_t size;
171 register char *p;
aae81fb4 172 char *start;
48f06ece
KB
173
174 if (!(size = sbp->st_size))
175 return;
176
aae81fb4 177 if ((start = mmap(NULL,
31919d23
KB
178 size, PROT_READ, MAP_FILE, fileno(fp), (off_t)0)) == (caddr_t)-1) {
179 err(0, "%s", strerror(errno));
180 return;
181 }
48f06ece
KB
182
183 /* Last char is special, ignore whether newline or not. */
aae81fb4 184 for (p = start + size - 1; --size;)
34554469
KB
185 if (*--p == '\n' && !--off) {
186 ++p;
48f06ece 187 break;
34554469 188 }
48f06ece
KB
189
190 /* Set the file pointer to reflect the length displayed. */
191 size = sbp->st_size - size;
34554469 192 WR(p, size);
31919d23 193 if (fseek(fp, sbp->st_size, SEEK_SET) == -1) {
48f06ece 194 ierr();
31919d23
KB
195 return;
196 }
aae81fb4
KB
197 if (munmap(start, size)) {
198 err(0, "%s", strerror(errno));
199 return;
200 }
48f06ece 201}