1209e49b2SChris Love /*
2209e49b2SChris Love * Copyright (c) 1991, 1993
3209e49b2SChris Love * The Regents of the University of California. All rights reserved.
4209e49b2SChris Love *
5209e49b2SChris Love * This code is derived from software contributed to Berkeley by
6209e49b2SChris Love * Edward Sze-Tyan Wang.
7209e49b2SChris Love *
8209e49b2SChris Love * Redistribution and use in source and binary forms, with or without
9209e49b2SChris Love * modification, are permitted provided that the following conditions
10209e49b2SChris Love * are met:
11209e49b2SChris Love * 1. Redistributions of source code must retain the above copyright
12209e49b2SChris Love * notice, this list of conditions and the following disclaimer.
13209e49b2SChris Love * 2. Redistributions in binary form must reproduce the above copyright
14209e49b2SChris Love * notice, this list of conditions and the following disclaimer in the
15209e49b2SChris Love * documentation and/or other materials provided with the distribution.
16209e49b2SChris Love * 4. Neither the name of the University nor the names of its contributors
17209e49b2SChris Love * may be used to endorse or promote products derived from this software
18209e49b2SChris Love * without specific prior written permission.
19209e49b2SChris Love *
20209e49b2SChris Love * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21209e49b2SChris Love * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22209e49b2SChris Love * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23209e49b2SChris Love * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24209e49b2SChris Love * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25209e49b2SChris Love * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26209e49b2SChris Love * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27209e49b2SChris Love * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28209e49b2SChris Love * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29209e49b2SChris Love * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30209e49b2SChris Love * SUCH DAMAGE.
31209e49b2SChris Love */
32209e49b2SChris Love
33209e49b2SChris Love /*
34*72102e74SBryan Cantrill * Copyright (c) 2013, Joyent, Inc. All rights reserved.
35209e49b2SChris Love */
36209e49b2SChris Love
37209e49b2SChris Love #include <sys/param.h>
38209e49b2SChris Love #include <sys/mount.h>
39209e49b2SChris Love #include <sys/types.h>
40209e49b2SChris Love #include <sys/stat.h>
41209e49b2SChris Love #include <sys/statfs.h>
42209e49b2SChris Love #include <sys/statvfs.h>
43209e49b2SChris Love #include <sys/time.h>
44209e49b2SChris Love #include <sys/mman.h>
45209e49b2SChris Love #include <sys/poll.h>
46209e49b2SChris Love #include <port.h>
47209e49b2SChris Love #include <err.h>
48209e49b2SChris Love #include <errno.h>
49209e49b2SChris Love #include <fcntl.h>
50209e49b2SChris Love #include <limits.h>
51209e49b2SChris Love #include <stdio.h>
52209e49b2SChris Love #include <stdlib.h>
53209e49b2SChris Love #include <string.h>
54*72102e74SBryan Cantrill #include <strings.h>
55209e49b2SChris Love #include <unistd.h>
56209e49b2SChris Love
57209e49b2SChris Love #include "extern.h"
58209e49b2SChris Love
59209e49b2SChris Love static void rlines(FILE *, const char *fn, off_t, struct stat *);
60209e49b2SChris Love static int show(file_info_t *);
61209e49b2SChris Love static void set_events(file_info_t *files);
62209e49b2SChris Love
63209e49b2SChris Love /* defines for inner loop actions */
64209e49b2SChris Love #define USE_SLEEP 0
65*72102e74SBryan Cantrill #define USE_PORT 1
66209e49b2SChris Love #define ADD_EVENTS 2
67209e49b2SChris Love
68*72102e74SBryan Cantrill int port;
69*72102e74SBryan Cantrill int action = USE_PORT;
70209e49b2SChris Love
71209e49b2SChris Love static const file_info_t *last;
72209e49b2SChris Love
73209e49b2SChris Love /*
74209e49b2SChris Love * forward -- display the file, from an offset, forward.
75209e49b2SChris Love *
76209e49b2SChris Love * There are eight separate cases for this -- regular and non-regular
77209e49b2SChris Love * files, by bytes or lines and from the beginning or end of the file.
78209e49b2SChris Love *
79209e49b2SChris Love * FBYTES byte offset from the beginning of the file
80209e49b2SChris Love * REG seek
81209e49b2SChris Love * NOREG read, counting bytes
82209e49b2SChris Love *
83209e49b2SChris Love * FLINES line offset from the beginning of the file
84209e49b2SChris Love * REG read, counting lines
85209e49b2SChris Love * NOREG read, counting lines
86209e49b2SChris Love *
87209e49b2SChris Love * RBYTES byte offset from the end of the file
88209e49b2SChris Love * REG seek
89209e49b2SChris Love * NOREG cyclically read characters into a wrap-around buffer
90209e49b2SChris Love *
91209e49b2SChris Love * RLINES
92209e49b2SChris Love * REG mmap the file and step back until reach the correct offset.
93209e49b2SChris Love * NOREG cyclically read lines into a wrap-around array of buffers
94209e49b2SChris Love */
95209e49b2SChris Love void
forward(FILE * fp,const char * fn,enum STYLE style,off_t off,struct stat * sbp)96209e49b2SChris Love forward(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
97209e49b2SChris Love {
98209e49b2SChris Love int ch;
99209e49b2SChris Love
100209e49b2SChris Love switch (style) {
101209e49b2SChris Love case FBYTES:
102209e49b2SChris Love if (off == 0)
103209e49b2SChris Love break;
104209e49b2SChris Love if (S_ISREG(sbp->st_mode)) {
105209e49b2SChris Love if (sbp->st_size < off)
106209e49b2SChris Love off = sbp->st_size;
107209e49b2SChris Love if (fseeko(fp, off, SEEK_SET) == -1) {
108209e49b2SChris Love ierr(fn);
109209e49b2SChris Love return;
110209e49b2SChris Love }
111209e49b2SChris Love } else while (off--)
112209e49b2SChris Love if ((ch = getc(fp)) == EOF) {
113209e49b2SChris Love if (ferror(fp)) {
114209e49b2SChris Love ierr(fn);
115209e49b2SChris Love return;
116209e49b2SChris Love }
117209e49b2SChris Love break;
118209e49b2SChris Love }
119209e49b2SChris Love break;
120209e49b2SChris Love case FLINES:
121209e49b2SChris Love if (off == 0)
122209e49b2SChris Love break;
123209e49b2SChris Love for (;;) {
124209e49b2SChris Love if ((ch = getc(fp)) == EOF) {
125209e49b2SChris Love if (ferror(fp)) {
126209e49b2SChris Love ierr(fn);
127209e49b2SChris Love return;
128209e49b2SChris Love }
129209e49b2SChris Love break;
130209e49b2SChris Love }
131209e49b2SChris Love if (ch == '\n' && !--off)
132209e49b2SChris Love break;
133209e49b2SChris Love }
134209e49b2SChris Love break;
135209e49b2SChris Love case RBYTES:
136209e49b2SChris Love if (S_ISREG(sbp->st_mode)) {
137209e49b2SChris Love if (sbp->st_size >= off &&
138209e49b2SChris Love fseeko(fp, -off, SEEK_END) == -1) {
139209e49b2SChris Love ierr(fn);
140209e49b2SChris Love return;
141209e49b2SChris Love }
142209e49b2SChris Love } else if (off == 0) {
143209e49b2SChris Love while (getc(fp) != EOF)
144209e49b2SChris Love ;
145209e49b2SChris Love if (ferror(fp)) {
146209e49b2SChris Love ierr(fn);
147209e49b2SChris Love return;
148209e49b2SChris Love }
149209e49b2SChris Love } else
150209e49b2SChris Love if (bytes(fp, fn, off))
151209e49b2SChris Love return;
152209e49b2SChris Love break;
153209e49b2SChris Love case RLINES:
154209e49b2SChris Love if (S_ISREG(sbp->st_mode))
155209e49b2SChris Love if (!off) {
156209e49b2SChris Love if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
157209e49b2SChris Love ierr(fn);
158209e49b2SChris Love return;
159209e49b2SChris Love }
160209e49b2SChris Love } else
161209e49b2SChris Love rlines(fp, fn, off, sbp);
162209e49b2SChris Love else if (off == 0) {
163209e49b2SChris Love while (getc(fp) != EOF)
164209e49b2SChris Love ;
165209e49b2SChris Love if (ferror(fp)) {
166209e49b2SChris Love ierr(fn);
167209e49b2SChris Love return;
168209e49b2SChris Love }
169209e49b2SChris Love } else
170209e49b2SChris Love if (lines(fp, fn, off))
171209e49b2SChris Love return;
172209e49b2SChris Love break;
173209e49b2SChris Love default:
174209e49b2SChris Love break;
175209e49b2SChris Love }
176209e49b2SChris Love
177209e49b2SChris Love while ((ch = getc(fp)) != EOF)
178209e49b2SChris Love if (putchar(ch) == EOF)
179209e49b2SChris Love oerr();
180209e49b2SChris Love if (ferror(fp)) {
181209e49b2SChris Love ierr(fn);
182209e49b2SChris Love return;
183209e49b2SChris Love }
184209e49b2SChris Love (void) fflush(stdout);
185209e49b2SChris Love }
186209e49b2SChris Love
187209e49b2SChris Love /*
188209e49b2SChris Love * rlines -- display the last offset lines of the file.
189209e49b2SChris Love */
190209e49b2SChris Love static void
rlines(FILE * fp,const char * fn,off_t off,struct stat * sbp)191209e49b2SChris Love rlines(FILE *fp, const char *fn, off_t off, struct stat *sbp)
192209e49b2SChris Love {
193209e49b2SChris Love struct mapinfo map;
194209e49b2SChris Love off_t curoff, size;
195209e49b2SChris Love int i;
196209e49b2SChris Love
197209e49b2SChris Love if ((size = sbp->st_size) == 0)
198209e49b2SChris Love return;
199209e49b2SChris Love map.start = NULL;
200209e49b2SChris Love map.fd = fileno(fp);
201209e49b2SChris Love map.mapoff = map.maxoff = size;
202209e49b2SChris Love
203209e49b2SChris Love /*
204209e49b2SChris Love * Last char is special, ignore whether newline or not. Note that
205209e49b2SChris Love * size == 0 is dealt with above, and size == 1 sets curoff to -1.
206209e49b2SChris Love */
207209e49b2SChris Love curoff = size - 2;
208209e49b2SChris Love while (curoff >= 0) {
209209e49b2SChris Love if (curoff < map.mapoff && maparound(&map, curoff) != 0) {
210209e49b2SChris Love ierr(fn);
211209e49b2SChris Love return;
212209e49b2SChris Love }
213209e49b2SChris Love for (i = curoff - map.mapoff; i >= 0; i--)
214209e49b2SChris Love if (map.start[i] == '\n' && --off == 0)
215209e49b2SChris Love break;
216209e49b2SChris Love /* `i' is either the map offset of a '\n', or -1. */
217209e49b2SChris Love curoff = map.mapoff + i;
218209e49b2SChris Love if (i >= 0)
219209e49b2SChris Love break;
220209e49b2SChris Love }
221209e49b2SChris Love curoff++;
222209e49b2SChris Love if (mapprint(&map, curoff, size - curoff) != 0) {
223209e49b2SChris Love ierr(fn);
224209e49b2SChris Love exit(1);
225209e49b2SChris Love }
226209e49b2SChris Love
227209e49b2SChris Love /* Set the file pointer to reflect the length displayed. */
228209e49b2SChris Love if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) {
229209e49b2SChris Love ierr(fn);
230209e49b2SChris Love return;
231209e49b2SChris Love }
232209e49b2SChris Love if (map.start != NULL && munmap(map.start, map.maplen)) {
233209e49b2SChris Love ierr(fn);
234209e49b2SChris Love return;
235209e49b2SChris Love }
236209e49b2SChris Love }
237209e49b2SChris Love
238209e49b2SChris Love static int
show(file_info_t * file)239209e49b2SChris Love show(file_info_t *file)
240209e49b2SChris Love {
241209e49b2SChris Love int ch;
242209e49b2SChris Love
243209e49b2SChris Love while ((ch = getc(file->fp)) != EOF) {
244209e49b2SChris Love if (last != file && no_files > 1) {
245209e49b2SChris Love if (!qflag)
246209e49b2SChris Love (void) printf("\n==> %s <==\n",
247209e49b2SChris Love file->file_name);
248209e49b2SChris Love last = file;
249209e49b2SChris Love }
250209e49b2SChris Love if (putchar(ch) == EOF)
251209e49b2SChris Love oerr();
252209e49b2SChris Love }
253209e49b2SChris Love (void) fflush(stdout);
254209e49b2SChris Love if (ferror(file->fp)) {
255209e49b2SChris Love (void) fclose(file->fp);
256209e49b2SChris Love file->fp = NULL;
257209e49b2SChris Love ierr(file->file_name);
258209e49b2SChris Love return (0);
259209e49b2SChris Love }
260209e49b2SChris Love clearerr(file->fp);
261209e49b2SChris Love return (1);
262209e49b2SChris Love }
263209e49b2SChris Love
264209e49b2SChris Love static void
associate(file_info_t * file,boolean_t assoc,port_event_t * ev)265*72102e74SBryan Cantrill associate(file_info_t *file, boolean_t assoc, port_event_t *ev)
266*72102e74SBryan Cantrill {
267*72102e74SBryan Cantrill char buf[64], *name;
268*72102e74SBryan Cantrill int i;
269*72102e74SBryan Cantrill
270*72102e74SBryan Cantrill if (action != USE_PORT || file->fp == NULL)
271*72102e74SBryan Cantrill return;
272*72102e74SBryan Cantrill
273*72102e74SBryan Cantrill if (!S_ISREG(file->st.st_mode)) {
274*72102e74SBryan Cantrill /*
275*72102e74SBryan Cantrill * For FIFOs, we use PORT_SOURCE_FD as our port event source.
276*72102e74SBryan Cantrill */
277*72102e74SBryan Cantrill if (assoc) {
278*72102e74SBryan Cantrill (void) port_associate(port, PORT_SOURCE_FD,
279*72102e74SBryan Cantrill fileno(file->fp), POLLIN, file);
280*72102e74SBryan Cantrill } else {
281*72102e74SBryan Cantrill (void) port_dissociate(port, PORT_SOURCE_FD,
282*72102e74SBryan Cantrill fileno(file->fp));
283*72102e74SBryan Cantrill }
284*72102e74SBryan Cantrill
285*72102e74SBryan Cantrill return;
286*72102e74SBryan Cantrill }
287*72102e74SBryan Cantrill
288*72102e74SBryan Cantrill bzero(&file->fobj, sizeof (file->fobj));
289*72102e74SBryan Cantrill
290*72102e74SBryan Cantrill if (!Fflag) {
291*72102e74SBryan Cantrill /*
292*72102e74SBryan Cantrill * PORT_SOURCE_FILE only allows us to specify a file name, not
293*72102e74SBryan Cantrill * a file descriptor. If we are following a specific file (as
294*72102e74SBryan Cantrill * opposed to a file name) and we were to specify the name of
295*72102e74SBryan Cantrill * the file to port_associate() and that file were moved
296*72102e74SBryan Cantrill * aside, we would not be able to reassociate an event because
297*72102e74SBryan Cantrill * we would not know a name that would resolve to the new file
298*72102e74SBryan Cantrill * (indeed, there might not be such a name -- the file may
299*72102e74SBryan Cantrill * have been unlinked). But there _is_ a name that we know
300*72102e74SBryan Cantrill * maps to the file and doesn't change: the name of the
301*72102e74SBryan Cantrill * representation of the open file descriptor in /proc. We
302*72102e74SBryan Cantrill * therefore associate with this name (and the underlying
303*72102e74SBryan Cantrill * file), not the name of the file as specified at the command
304*72102e74SBryan Cantrill * line. This also has the (desirable) side-effect of
305*72102e74SBryan Cantrill * insulating against FILE_RENAME_FROM and FILE_RENAME_TO
306*72102e74SBryan Cantrill * events that we need to ignore to assure that we don't lose
307*72102e74SBryan Cantrill * FILE_TRUNC events.
308*72102e74SBryan Cantrill */
309*72102e74SBryan Cantrill (void) snprintf(buf,
310*72102e74SBryan Cantrill sizeof (buf), "/proc/self/fd/%d", fileno(file->fp));
311*72102e74SBryan Cantrill name = buf;
312*72102e74SBryan Cantrill } else {
313*72102e74SBryan Cantrill name = file->file_name;
314*72102e74SBryan Cantrill }
315*72102e74SBryan Cantrill
316*72102e74SBryan Cantrill /*
317*72102e74SBryan Cantrill * Note that portfs uses the address of the specified file_obj_t to
318*72102e74SBryan Cantrill * tag an association; if one creates a different association with a
319*72102e74SBryan Cantrill * (different) file_obj_t that happens to be at the same address,
320*72102e74SBryan Cantrill * the first association will be implicitly removed. To assure that
321*72102e74SBryan Cantrill * each association has a disjoint file_obj_t, we allocate the memory
322*72102e74SBryan Cantrill * for each in the file_info, not on the stack.
323*72102e74SBryan Cantrill */
324*72102e74SBryan Cantrill file->fobj[0].fo_name = name;
325*72102e74SBryan Cantrill file->fobj[1].fo_name = name;
326*72102e74SBryan Cantrill
327*72102e74SBryan Cantrill if (assoc) {
328*72102e74SBryan Cantrill /*
329*72102e74SBryan Cantrill * To assure that we cannot possibly drop a FILE_TRUNC event,
330*72102e74SBryan Cantrill * we have two different PORT_SOURCE_FILE associations with the
331*72102e74SBryan Cantrill * port: one to get only FILE_MODIFIED events and another to
332*72102e74SBryan Cantrill * get only FILE_TRUNC events. This assures that we always
333*72102e74SBryan Cantrill * have an active association for FILE_TRUNC events when the
334*72102e74SBryan Cantrill * seek offset is non-zero. Note that the association order
335*72102e74SBryan Cantrill * _must_ be FILE_TRUNC followed by FILE_MODIFIED: if a single
336*72102e74SBryan Cantrill * event induces both a FILE_TRUNC and a FILE_MODIFIED (as
337*72102e74SBryan Cantrill * a VE_CREATE vnode event does), we must process the
338*72102e74SBryan Cantrill * FILE_TRUNC before FILE_MODIFIED -- and the order in which
339*72102e74SBryan Cantrill * these are processed will be the association order. So
340*72102e74SBryan Cantrill * if we see a FILE_TRUNC, we dissociate/reassociate the
341*72102e74SBryan Cantrill * FILE_MODIFIED association.
342*72102e74SBryan Cantrill */
343*72102e74SBryan Cantrill if (ev == NULL || (ev->portev_events & FILE_TRUNC) ||
344*72102e74SBryan Cantrill !(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) {
345*72102e74SBryan Cantrill (void) port_associate(port, PORT_SOURCE_FILE,
346*72102e74SBryan Cantrill (uintptr_t)&file->fobj[0], FILE_TRUNC, file);
347*72102e74SBryan Cantrill (void) port_dissociate(port, PORT_SOURCE_FILE,
348*72102e74SBryan Cantrill (uintptr_t)&file->fobj[1]);
349*72102e74SBryan Cantrill ev = NULL;
350*72102e74SBryan Cantrill }
351*72102e74SBryan Cantrill
352*72102e74SBryan Cantrill if (ev == NULL || (ev->portev_events & FILE_MODIFIED) ||
353*72102e74SBryan Cantrill !(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) {
354*72102e74SBryan Cantrill (void) port_associate(port, PORT_SOURCE_FILE,
355*72102e74SBryan Cantrill (uintptr_t)&file->fobj[1], FILE_MODIFIED, file);
356*72102e74SBryan Cantrill }
357*72102e74SBryan Cantrill } else {
358*72102e74SBryan Cantrill for (i = 0; i <= 1; i++) {
359*72102e74SBryan Cantrill (void) port_dissociate(port, PORT_SOURCE_FILE,
360*72102e74SBryan Cantrill (uintptr_t)&file->fobj[i]);
361*72102e74SBryan Cantrill }
362*72102e74SBryan Cantrill }
363*72102e74SBryan Cantrill }
364*72102e74SBryan Cantrill
365*72102e74SBryan Cantrill static void
set_events(file_info_t * files)366209e49b2SChris Love set_events(file_info_t *files)
367209e49b2SChris Love {
368209e49b2SChris Love int i;
369209e49b2SChris Love file_info_t *file;
370209e49b2SChris Love
371209e49b2SChris Love for (i = 0, file = files; i < no_files; i++, file++) {
372209e49b2SChris Love if (! file->fp)
373209e49b2SChris Love continue;
374209e49b2SChris Love
375209e49b2SChris Love (void) fstat(fileno(file->fp), &file->st);
376*72102e74SBryan Cantrill
377*72102e74SBryan Cantrill associate(file, B_TRUE, NULL);
378209e49b2SChris Love }
379209e49b2SChris Love }
380209e49b2SChris Love
381209e49b2SChris Love /*
382209e49b2SChris Love * follow -- display the file, from an offset, forward.
383209e49b2SChris Love *
384209e49b2SChris Love */
385209e49b2SChris Love void
follow(file_info_t * files,enum STYLE style,off_t off)386209e49b2SChris Love follow(file_info_t *files, enum STYLE style, off_t off)
387209e49b2SChris Love {
388209e49b2SChris Love int active, ev_change, i, n = -1;
389209e49b2SChris Love struct stat sb2;
390209e49b2SChris Love file_info_t *file;
391*72102e74SBryan Cantrill struct timespec ts;
392*72102e74SBryan Cantrill port_event_t ev;
393209e49b2SChris Love
394209e49b2SChris Love /* Position each of the files */
395209e49b2SChris Love
396209e49b2SChris Love file = files;
397209e49b2SChris Love active = 0;
398209e49b2SChris Love n = 0;
399209e49b2SChris Love for (i = 0; i < no_files; i++, file++) {
400209e49b2SChris Love if (file->fp) {
401209e49b2SChris Love active = 1;
402209e49b2SChris Love n++;
403209e49b2SChris Love if (no_files > 1 && !qflag)
404209e49b2SChris Love (void) printf("\n==> %s <==\n",
405209e49b2SChris Love file->file_name);
406209e49b2SChris Love forward(file->fp, file->file_name, style, off,
407209e49b2SChris Love &file->st);
408209e49b2SChris Love if (Fflag && fileno(file->fp) != STDIN_FILENO)
409209e49b2SChris Love n++;
410209e49b2SChris Love }
411209e49b2SChris Love }
412209e49b2SChris Love if (!Fflag && !active)
413209e49b2SChris Love return;
414209e49b2SChris Love
415209e49b2SChris Love last = --file;
416*72102e74SBryan Cantrill
417*72102e74SBryan Cantrill if (action == USE_PORT &&
418*72102e74SBryan Cantrill (stat("/proc/self/fd", &sb2) == -1 || !S_ISDIR(sb2.st_mode) ||
419*72102e74SBryan Cantrill (port = port_create()) == -1))
420*72102e74SBryan Cantrill action = USE_SLEEP;
421*72102e74SBryan Cantrill
422209e49b2SChris Love set_events(files);
423209e49b2SChris Love
424209e49b2SChris Love for (;;) {
425209e49b2SChris Love ev_change = 0;
426209e49b2SChris Love if (Fflag) {
427209e49b2SChris Love for (i = 0, file = files; i < no_files; i++, file++) {
428209e49b2SChris Love if (!file->fp) {
429209e49b2SChris Love file->fp = fopen(file->file_name, "r");
430209e49b2SChris Love if (file->fp != NULL &&
431209e49b2SChris Love fstat(fileno(file->fp), &file->st)
432209e49b2SChris Love == -1) {
433209e49b2SChris Love (void) fclose(file->fp);
434209e49b2SChris Love file->fp = NULL;
435209e49b2SChris Love }
436209e49b2SChris Love if (file->fp != NULL)
437209e49b2SChris Love ev_change++;
438209e49b2SChris Love continue;
439209e49b2SChris Love }
440209e49b2SChris Love if (fileno(file->fp) == STDIN_FILENO)
441209e49b2SChris Love continue;
442209e49b2SChris Love if (stat(file->file_name, &sb2) == -1) {
443209e49b2SChris Love if (errno != ENOENT)
444209e49b2SChris Love ierr(file->file_name);
445209e49b2SChris Love (void) show(file);
446209e49b2SChris Love (void) fclose(file->fp);
447209e49b2SChris Love file->fp = NULL;
448209e49b2SChris Love ev_change++;
449209e49b2SChris Love continue;
450209e49b2SChris Love }
451209e49b2SChris Love
452209e49b2SChris Love if (sb2.st_ino != file->st.st_ino ||
453209e49b2SChris Love sb2.st_dev != file->st.st_dev ||
454209e49b2SChris Love sb2.st_nlink == 0) {
455209e49b2SChris Love (void) show(file);
456*72102e74SBryan Cantrill associate(file, B_FALSE, NULL);
457209e49b2SChris Love file->fp = freopen(file->file_name, "r",
458209e49b2SChris Love file->fp);
459*72102e74SBryan Cantrill if (file->fp != NULL) {
460209e49b2SChris Love (void) memcpy(&file->st, &sb2,
461209e49b2SChris Love sizeof (struct stat));
462*72102e74SBryan Cantrill } else if (errno != ENOENT)
463209e49b2SChris Love ierr(file->file_name);
464209e49b2SChris Love ev_change++;
465209e49b2SChris Love }
466209e49b2SChris Love }
467209e49b2SChris Love }
468209e49b2SChris Love
469209e49b2SChris Love for (i = 0, file = files; i < no_files; i++, file++)
470209e49b2SChris Love if (file->fp && !show(file))
471209e49b2SChris Love ev_change++;
472209e49b2SChris Love
473209e49b2SChris Love if (ev_change)
474209e49b2SChris Love set_events(files);
475209e49b2SChris Love
476209e49b2SChris Love switch (action) {
477*72102e74SBryan Cantrill case USE_PORT:
478*72102e74SBryan Cantrill ts.tv_sec = 1;
479*72102e74SBryan Cantrill ts.tv_nsec = 0;
480*72102e74SBryan Cantrill
481*72102e74SBryan Cantrill /*
482*72102e74SBryan Cantrill * In the -F case we set a timeout to ensure that
483*72102e74SBryan Cantrill * we re-stat the file at least once every second.
484*72102e74SBryan Cantrill */
485*72102e74SBryan Cantrill n = port_get(port, &ev, Fflag ? &ts : NULL);
486*72102e74SBryan Cantrill
487*72102e74SBryan Cantrill if (n == 0) {
488*72102e74SBryan Cantrill file = (file_info_t *)ev.portev_user;
489*72102e74SBryan Cantrill associate(file, B_TRUE, &ev);
490*72102e74SBryan Cantrill
491*72102e74SBryan Cantrill if (ev.portev_events & FILE_TRUNC)
492*72102e74SBryan Cantrill (void) fseek(file->fp, 0, SEEK_SET);
493*72102e74SBryan Cantrill }
494*72102e74SBryan Cantrill
495*72102e74SBryan Cantrill break;
496*72102e74SBryan Cantrill
497209e49b2SChris Love case USE_SLEEP:
498209e49b2SChris Love (void) usleep(250000);
499209e49b2SChris Love break;
500209e49b2SChris Love }
501209e49b2SChris Love }
502209e49b2SChris Love }
503