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 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 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 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 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 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 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