19b50d902SRodney W. Grimes /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1991, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * This code is derived from software contributed to Berkeley by
89b50d902SRodney W. Grimes * Edward Sze-Tyan Wang.
99b50d902SRodney W. Grimes *
109b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
119b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
129b50d902SRodney W. Grimes * are met:
139b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
149b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
159b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
169b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
179b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
199b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
209b50d902SRodney W. Grimes * without specific prior written permission.
219b50d902SRodney W. Grimes *
229b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329b50d902SRodney W. Grimes * SUCH DAMAGE.
339b50d902SRodney W. Grimes */
349b50d902SRodney W. Grimes
35814e3a92SMark Murray
369b50d902SRodney W. Grimes
3713829828SPaul Saab #include <sys/param.h>
3813829828SPaul Saab #include <sys/mount.h>
399b50d902SRodney W. Grimes #include <sys/types.h>
409b50d902SRodney W. Grimes #include <sys/stat.h>
419b50d902SRodney W. Grimes #include <sys/time.h>
429b50d902SRodney W. Grimes #include <sys/mman.h>
4332462e82SJonathan Lemon #include <sys/event.h>
449b50d902SRodney W. Grimes
45814e3a92SMark Murray #include <err.h>
469b50d902SRodney W. Grimes #include <errno.h>
47814e3a92SMark Murray #include <fcntl.h>
48814e3a92SMark Murray #include <limits.h>
499b50d902SRodney W. Grimes #include <stdio.h>
509b50d902SRodney W. Grimes #include <stdlib.h>
519b50d902SRodney W. Grimes #include <string.h>
52814e3a92SMark Murray #include <unistd.h>
53814e3a92SMark Murray
54c851fce6SMariusz Zaborski #include <libcasper.h>
55c851fce6SMariusz Zaborski #include <casper/cap_fileargs.h>
56c851fce6SMariusz Zaborski
579b50d902SRodney W. Grimes #include "extern.h"
589b50d902SRodney W. Grimes
5922da50cfSBrian Somers static void rlines(FILE *, const char *fn, off_t, struct stat *);
6022da50cfSBrian Somers static int show(file_info_t *);
61a2fb00d9SDavid Malone static void set_events(file_info_t *files);
629b50d902SRodney W. Grimes
63ea9bd2dfSJonathan Lemon /* defines for inner loop actions */
64ea9bd2dfSJonathan Lemon #define USE_SLEEP 0
65ea9bd2dfSJonathan Lemon #define USE_KQUEUE 1
66ea9bd2dfSJonathan Lemon #define ADD_EVENTS 2
67ea9bd2dfSJonathan Lemon
68c7c497f1SEd Schouten static struct kevent *ev;
69c7c497f1SEd Schouten static int action = USE_SLEEP;
70c7c497f1SEd Schouten static int kq;
7115a55f79SPaul Richards
7276628ce7SXin LI static const file_info_t *last;
7376628ce7SXin LI
749b50d902SRodney W. Grimes /*
759b50d902SRodney W. Grimes * forward -- display the file, from an offset, forward.
769b50d902SRodney W. Grimes *
779b50d902SRodney W. Grimes * There are eight separate cases for this -- regular and non-regular
789b50d902SRodney W. Grimes * files, by bytes or lines and from the beginning or end of the file.
799b50d902SRodney W. Grimes *
809b50d902SRodney W. Grimes * FBYTES byte offset from the beginning of the file
819b50d902SRodney W. Grimes * REG seek
829b50d902SRodney W. Grimes * NOREG read, counting bytes
839b50d902SRodney W. Grimes *
849b50d902SRodney W. Grimes * FLINES line offset from the beginning of the file
859b50d902SRodney W. Grimes * REG read, counting lines
869b50d902SRodney W. Grimes * NOREG read, counting lines
879b50d902SRodney W. Grimes *
889b50d902SRodney W. Grimes * RBYTES byte offset from the end of the file
899b50d902SRodney W. Grimes * REG seek
909b50d902SRodney W. Grimes * NOREG cyclically read characters into a wrap-around buffer
919b50d902SRodney W. Grimes *
929b50d902SRodney W. Grimes * RLINES
939b50d902SRodney W. Grimes * REG mmap the file and step back until reach the correct offset.
949b50d902SRodney W. Grimes * NOREG cyclically read lines into a wrap-around array of buffers
959b50d902SRodney W. Grimes */
969b50d902SRodney W. Grimes void
forward(FILE * fp,const char * fn,enum STYLE style,off_t off,struct stat * sbp)9722da50cfSBrian Somers forward(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp)
989b50d902SRodney W. Grimes {
99a2fb00d9SDavid Malone int ch;
1009b50d902SRodney W. Grimes
1019b50d902SRodney W. Grimes switch(style) {
1029b50d902SRodney W. Grimes case FBYTES:
1039b50d902SRodney W. Grimes if (off == 0)
1049b50d902SRodney W. Grimes break;
1051fb3caeeSRicardo Branco if (S_ISREG(sbp->st_mode) && sbp->st_size > 0) {
1069b50d902SRodney W. Grimes if (sbp->st_size < off)
1079b50d902SRodney W. Grimes off = sbp->st_size;
108bd9dc975SAndrey A. Chernov if (fseeko(fp, off, SEEK_SET) == -1) {
10922da50cfSBrian Somers ierr(fn);
1109b50d902SRodney W. Grimes return;
1119b50d902SRodney W. Grimes }
1129b50d902SRodney W. Grimes } else while (off--)
1139b50d902SRodney W. Grimes if ((ch = getc(fp)) == EOF) {
1149b50d902SRodney W. Grimes if (ferror(fp)) {
11522da50cfSBrian Somers ierr(fn);
1169b50d902SRodney W. Grimes return;
1179b50d902SRodney W. Grimes }
1189b50d902SRodney W. Grimes break;
1199b50d902SRodney W. Grimes }
1209b50d902SRodney W. Grimes break;
1219b50d902SRodney W. Grimes case FLINES:
1229b50d902SRodney W. Grimes if (off == 0)
1239b50d902SRodney W. Grimes break;
1249b50d902SRodney W. Grimes for (;;) {
1259b50d902SRodney W. Grimes if ((ch = getc(fp)) == EOF) {
1269b50d902SRodney W. Grimes if (ferror(fp)) {
12722da50cfSBrian Somers ierr(fn);
1289b50d902SRodney W. Grimes return;
1299b50d902SRodney W. Grimes }
1309b50d902SRodney W. Grimes break;
1319b50d902SRodney W. Grimes }
1329b50d902SRodney W. Grimes if (ch == '\n' && !--off)
1339b50d902SRodney W. Grimes break;
1349b50d902SRodney W. Grimes }
1359b50d902SRodney W. Grimes break;
1369b50d902SRodney W. Grimes case RBYTES:
1371fb3caeeSRicardo Branco if (S_ISREG(sbp->st_mode) && sbp->st_size > 0) {
1389b50d902SRodney W. Grimes if (sbp->st_size >= off &&
139bd9dc975SAndrey A. Chernov fseeko(fp, -off, SEEK_END) == -1) {
14022da50cfSBrian Somers ierr(fn);
1419b50d902SRodney W. Grimes return;
1429b50d902SRodney W. Grimes }
1439b50d902SRodney W. Grimes } else if (off == 0) {
1449b50d902SRodney W. Grimes while (getc(fp) != EOF);
1459b50d902SRodney W. Grimes if (ferror(fp)) {
14622da50cfSBrian Somers ierr(fn);
1479b50d902SRodney W. Grimes return;
1489b50d902SRodney W. Grimes }
1499b50d902SRodney W. Grimes } else
15022da50cfSBrian Somers if (bytes(fp, fn, off))
1516439f56eSAdam David return;
1529b50d902SRodney W. Grimes break;
1539b50d902SRodney W. Grimes case RLINES:
1541fb3caeeSRicardo Branco if (S_ISREG(sbp->st_mode) && sbp->st_size > 0)
1559b50d902SRodney W. Grimes if (!off) {
156bd9dc975SAndrey A. Chernov if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
15722da50cfSBrian Somers ierr(fn);
1589b50d902SRodney W. Grimes return;
1599b50d902SRodney W. Grimes }
1609b50d902SRodney W. Grimes } else
16122da50cfSBrian Somers rlines(fp, fn, off, sbp);
1629b50d902SRodney W. Grimes else if (off == 0) {
1639b50d902SRodney W. Grimes while (getc(fp) != EOF);
1649b50d902SRodney W. Grimes if (ferror(fp)) {
16522da50cfSBrian Somers ierr(fn);
1669b50d902SRodney W. Grimes return;
1679b50d902SRodney W. Grimes }
1689b50d902SRodney W. Grimes } else
16922da50cfSBrian Somers if (lines(fp, fn, off))
1706439f56eSAdam David return;
1719b50d902SRodney W. Grimes break;
172814e3a92SMark Murray default:
173b77b9b9aSMurray Stokely break;
1749b50d902SRodney W. Grimes }
1759b50d902SRodney W. Grimes
1769b50d902SRodney W. Grimes while ((ch = getc(fp)) != EOF)
1779b50d902SRodney W. Grimes if (putchar(ch) == EOF)
1789b50d902SRodney W. Grimes oerr();
1799b50d902SRodney W. Grimes if (ferror(fp)) {
18022da50cfSBrian Somers ierr(fn);
1819b50d902SRodney W. Grimes return;
1829b50d902SRodney W. Grimes }
1839b50d902SRodney W. Grimes (void)fflush(stdout);
1849b50d902SRodney W. Grimes }
1859b50d902SRodney W. Grimes
1869b50d902SRodney W. Grimes /*
1879b50d902SRodney W. Grimes * rlines -- display the last offset lines of the file.
1889b50d902SRodney W. Grimes */
1899b50d902SRodney W. Grimes static void
rlines(FILE * fp,const char * fn,off_t off,struct stat * sbp)19022da50cfSBrian Somers rlines(FILE *fp, const char *fn, off_t off, struct stat *sbp)
1919b50d902SRodney W. Grimes {
192726098d3SDavid Malone struct mapinfo map;
193726098d3SDavid Malone off_t curoff, size;
194726098d3SDavid Malone int i;
1959b50d902SRodney W. Grimes
1969b50d902SRodney W. Grimes if (!(size = sbp->st_size))
1979b50d902SRodney W. Grimes return;
198726098d3SDavid Malone map.start = NULL;
199726098d3SDavid Malone map.fd = fileno(fp);
200726098d3SDavid Malone map.mapoff = map.maxoff = size;
2019b50d902SRodney W. Grimes
2026bea9ab4SAndrey A. Chernov /*
203726098d3SDavid Malone * Last char is special, ignore whether newline or not. Note that
204726098d3SDavid Malone * size == 0 is dealt with above, and size == 1 sets curoff to -1.
2056bea9ab4SAndrey A. Chernov */
206726098d3SDavid Malone curoff = size - 2;
207726098d3SDavid Malone while (curoff >= 0) {
208726098d3SDavid Malone if (curoff < map.mapoff && maparound(&map, curoff) != 0) {
20922da50cfSBrian Somers ierr(fn);
2109b50d902SRodney W. Grimes return;
2119b50d902SRodney W. Grimes }
212726098d3SDavid Malone for (i = curoff - map.mapoff; i >= 0; i--)
213726098d3SDavid Malone if (map.start[i] == '\n' && --off == 0)
214726098d3SDavid Malone break;
215726098d3SDavid Malone /* `i' is either the map offset of a '\n', or -1. */
216726098d3SDavid Malone curoff = map.mapoff + i;
217726098d3SDavid Malone if (i >= 0)
218726098d3SDavid Malone break;
219726098d3SDavid Malone }
220726098d3SDavid Malone curoff++;
221726098d3SDavid Malone if (mapprint(&map, curoff, size - curoff) != 0) {
22222da50cfSBrian Somers ierr(fn);
223726098d3SDavid Malone exit(1);
224726098d3SDavid Malone }
225726098d3SDavid Malone
226726098d3SDavid Malone /* Set the file pointer to reflect the length displayed. */
227a74da62eSAndrey A. Chernov if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) {
22822da50cfSBrian Somers ierr(fn);
229726098d3SDavid Malone return;
230726098d3SDavid Malone }
231726098d3SDavid Malone if (map.start != NULL && munmap(map.start, map.maplen)) {
23222da50cfSBrian Somers ierr(fn);
2339b50d902SRodney W. Grimes return;
2349b50d902SRodney W. Grimes }
2359b50d902SRodney W. Grimes }
23615a55f79SPaul Richards
23722da50cfSBrian Somers static int
show(file_info_t * file)23815a55f79SPaul Richards show(file_info_t *file)
23915a55f79SPaul Richards {
2409e777bc6SBrian Somers int ch;
24115a55f79SPaul Richards
24215a55f79SPaul Richards while ((ch = getc(file->fp)) != EOF) {
243643ac419SXin LI if (last != file) {
244643ac419SXin LI if (vflag || (qflag == 0 && no_files > 1))
245849d265dSJaakko Heinonen printfn(file->file_name, 1);
2469e777bc6SBrian Somers last = file;
24715a55f79SPaul Richards }
24815a55f79SPaul Richards if (putchar(ch) == EOF)
24915a55f79SPaul Richards oerr();
25015a55f79SPaul Richards }
25115a55f79SPaul Richards (void)fflush(stdout);
25215a55f79SPaul Richards if (ferror(file->fp)) {
25322da50cfSBrian Somers fclose(file->fp);
25415a55f79SPaul Richards file->fp = NULL;
25522da50cfSBrian Somers ierr(file->file_name);
25622da50cfSBrian Somers return 0;
25722da50cfSBrian Somers }
25815a55f79SPaul Richards clearerr(file->fp);
25922da50cfSBrian Somers return 1;
26015a55f79SPaul Richards }
26115a55f79SPaul Richards
262a2fb00d9SDavid Malone static void
set_events(file_info_t * files)26315a55f79SPaul Richards set_events(file_info_t *files)
26415a55f79SPaul Richards {
26515a55f79SPaul Richards int i, n = 0;
26615a55f79SPaul Richards file_info_t *file;
26715a55f79SPaul Richards struct timespec ts;
26813829828SPaul Saab struct statfs sf;
26915a55f79SPaul Richards
27015a55f79SPaul Richards ts.tv_sec = 0;
27115a55f79SPaul Richards ts.tv_nsec = 0;
27215a55f79SPaul Richards
27315a55f79SPaul Richards action = USE_KQUEUE;
27415a55f79SPaul Richards for (i = 0, file = files; i < no_files; i++, file++) {
27515a55f79SPaul Richards if (!file->fp)
27615a55f79SPaul Richards continue;
27713829828SPaul Saab
27813829828SPaul Saab if (fstatfs(fileno(file->fp), &sf) == 0 &&
27913829828SPaul Saab (sf.f_flags & MNT_LOCAL) == 0) {
28013829828SPaul Saab action = USE_SLEEP;
28113829828SPaul Saab return;
28213829828SPaul Saab }
28313829828SPaul Saab
28415a55f79SPaul Richards if (Fflag && fileno(file->fp) != STDIN_FILENO) {
28515a55f79SPaul Richards EV_SET(&ev[n], fileno(file->fp), EVFILT_VNODE,
28615a55f79SPaul Richards EV_ADD | EV_ENABLE | EV_CLEAR,
28715a55f79SPaul Richards NOTE_DELETE | NOTE_RENAME, 0, 0);
28815a55f79SPaul Richards n++;
28915a55f79SPaul Richards }
29015a55f79SPaul Richards EV_SET(&ev[n], fileno(file->fp), EVFILT_READ,
29115a55f79SPaul Richards EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0);
29215a55f79SPaul Richards n++;
29315a55f79SPaul Richards }
29415a55f79SPaul Richards
29515a55f79SPaul Richards if (kevent(kq, ev, n, NULL, 0, &ts) < 0) {
29615a55f79SPaul Richards action = USE_SLEEP;
29715a55f79SPaul Richards }
29815a55f79SPaul Richards }
29915a55f79SPaul Richards
30076628ce7SXin LI /*
30176628ce7SXin LI * follow -- display the file, from an offset, forward.
30276628ce7SXin LI *
30376628ce7SXin LI */
30415a55f79SPaul Richards void
follow(file_info_t * files,enum STYLE style,off_t off)30515a55f79SPaul Richards follow(file_info_t *files, enum STYLE style, off_t off)
30615a55f79SPaul Richards {
307621f4553SDag-Erling Smørgrav int active, ev_change, i, n;
30815a55f79SPaul Richards struct stat sb2;
30915a55f79SPaul Richards file_info_t *file;
310c851fce6SMariusz Zaborski FILE *ftmp;
31115a55f79SPaul Richards struct timespec ts;
31215a55f79SPaul Richards
31315a55f79SPaul Richards /* Position each of the files */
31415a55f79SPaul Richards active = 0;
315621f4553SDag-Erling Smørgrav for (i = 0, file = files; i < no_files; i++, file++) {
316621f4553SDag-Erling Smørgrav if (!file->fp)
317621f4553SDag-Erling Smørgrav continue;
31815a55f79SPaul Richards active = 1;
319643ac419SXin LI if (vflag || (qflag == 0 && no_files > 1))
320849d265dSJaakko Heinonen printfn(file->file_name, 1);
32122da50cfSBrian Somers forward(file->fp, file->file_name, style, off, &file->st);
32215a55f79SPaul Richards }
32322da50cfSBrian Somers if (!Fflag && !active)
32415a55f79SPaul Richards return;
32515a55f79SPaul Richards
32676628ce7SXin LI last = --file;
32776628ce7SXin LI
32815a55f79SPaul Richards kq = kqueue();
32915a55f79SPaul Richards if (kq < 0)
33015a55f79SPaul Richards err(1, "kqueue");
331621f4553SDag-Erling Smørgrav /*
332621f4553SDag-Erling Smørgrav * The number of kqueue events we track may vary over time and may
333621f4553SDag-Erling Smørgrav * even grow past its initial value in the -F case, but it will
334621f4553SDag-Erling Smørgrav * never exceed two per file, so just preallocate that.
335621f4553SDag-Erling Smørgrav */
336621f4553SDag-Erling Smørgrav ev = malloc(no_files * 2 * sizeof(struct kevent));
337621f4553SDag-Erling Smørgrav if (ev == NULL)
338b70e57beSDag-Erling Smørgrav err(1, "failed to allocate memory for kevents");
33915a55f79SPaul Richards set_events(files);
34015a55f79SPaul Richards
34115a55f79SPaul Richards for (;;) {
34222da50cfSBrian Somers ev_change = 0;
34322da50cfSBrian Somers if (Fflag) {
34415a55f79SPaul Richards for (i = 0, file = files; i < no_files; i++, file++) {
34522da50cfSBrian Somers if (!file->fp) {
346c851fce6SMariusz Zaborski file->fp =
347c851fce6SMariusz Zaborski fileargs_fopen(fa, file->file_name,
348c851fce6SMariusz Zaborski "r");
34922da50cfSBrian Somers if (file->fp != NULL &&
35022da50cfSBrian Somers fstat(fileno(file->fp), &file->st)
35122da50cfSBrian Somers == -1) {
35222da50cfSBrian Somers fclose(file->fp);
35322da50cfSBrian Somers file->fp = NULL;
35422da50cfSBrian Somers }
35522da50cfSBrian Somers if (file->fp != NULL)
35622da50cfSBrian Somers ev_change++;
35715a55f79SPaul Richards continue;
35822da50cfSBrian Somers }
35922da50cfSBrian Somers if (fileno(file->fp) == STDIN_FILENO)
36022da50cfSBrian Somers continue;
361c851fce6SMariusz Zaborski ftmp = fileargs_fopen(fa, file->file_name, "r");
362c851fce6SMariusz Zaborski if (ftmp == NULL ||
3637787e7eeSChuck Silvers fstat(fileno(ftmp), &sb2) == -1) {
36422da50cfSBrian Somers if (errno != ENOENT)
36522da50cfSBrian Somers ierr(file->file_name);
36622da50cfSBrian Somers show(file);
36754d34ff6SJilles Tjoelker if (file->fp != NULL) {
36822da50cfSBrian Somers fclose(file->fp);
36922da50cfSBrian Somers file->fp = NULL;
37054d34ff6SJilles Tjoelker }
371c851fce6SMariusz Zaborski if (ftmp != NULL) {
372c851fce6SMariusz Zaborski fclose(ftmp);
373c851fce6SMariusz Zaborski }
37422da50cfSBrian Somers ev_change++;
37522da50cfSBrian Somers continue;
37622da50cfSBrian Somers }
37722da50cfSBrian Somers
37822da50cfSBrian Somers if (sb2.st_ino != file->st.st_ino ||
37915a55f79SPaul Richards sb2.st_dev != file->st.st_dev ||
38022da50cfSBrian Somers sb2.st_nlink == 0) {
381d5d2cea1SMarcel Moolenaar show(file);
382*308399a1SAndre Albsmeier if (file->fp != NULL)
383c851fce6SMariusz Zaborski fclose(file->fp);
384c851fce6SMariusz Zaborski file->fp = ftmp;
38522da50cfSBrian Somers memcpy(&file->st, &sb2,
38622da50cfSBrian Somers sizeof(struct stat));
38722da50cfSBrian Somers ev_change++;
388c851fce6SMariusz Zaborski } else {
389c851fce6SMariusz Zaborski fclose(ftmp);
39022da50cfSBrian Somers }
39122da50cfSBrian Somers }
39222da50cfSBrian Somers }
39322da50cfSBrian Somers
39422da50cfSBrian Somers for (i = 0, file = files; i < no_files; i++, file++)
39522da50cfSBrian Somers if (file->fp && !show(file))
39622da50cfSBrian Somers ev_change++;
39722da50cfSBrian Somers
39822da50cfSBrian Somers if (ev_change)
39915a55f79SPaul Richards set_events(files);
40015a55f79SPaul Richards
40115a55f79SPaul Richards switch (action) {
40215a55f79SPaul Richards case USE_KQUEUE:
40315a55f79SPaul Richards ts.tv_sec = 1;
40415a55f79SPaul Richards ts.tv_nsec = 0;
40515a55f79SPaul Richards /*
40615a55f79SPaul Richards * In the -F case we set a timeout to ensure that
40715a55f79SPaul Richards * we re-stat the file at least once every second.
408c58205beSGordon Bergling * If we've received EINTR, ignore it. Both reasons
409ef6f20ceSWarner Losh * for its generation are transient.
41015a55f79SPaul Richards */
411ef6f20ceSWarner Losh do {
41215a55f79SPaul Richards n = kevent(kq, NULL, 0, ev, 1, Fflag ? &ts : NULL);
413621f4553SDag-Erling Smørgrav if (n < 0 && errno != EINTR)
41415a55f79SPaul Richards err(1, "kevent");
415ef6f20ceSWarner Losh } while (n < 0);
41615a55f79SPaul Richards if (n == 0) {
41715a55f79SPaul Richards /* timeout */
41815a55f79SPaul Richards break;
41915a55f79SPaul Richards } else if (ev->filter == EVFILT_READ && ev->data < 0) {
42015a55f79SPaul Richards /* file shrank, reposition to end */
42115a55f79SPaul Richards if (lseek(ev->ident, (off_t)0, SEEK_END) == -1) {
42222da50cfSBrian Somers ierr(file->file_name);
42315a55f79SPaul Richards continue;
42415a55f79SPaul Richards }
42515a55f79SPaul Richards }
42615a55f79SPaul Richards break;
42715a55f79SPaul Richards
42815a55f79SPaul Richards case USE_SLEEP:
42915a55f79SPaul Richards (void) usleep(250000);
43015a55f79SPaul Richards break;
43115a55f79SPaul Richards }
43215a55f79SPaul Richards }
43315a55f79SPaul Richards }
434