Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Nov 2001 14:00:02 -0800 (PST)
From:      Maxim Konovalov <maxim@macomnet.ru>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/24955:/usr/bin/tail -F in 4.1+ doesn't work if file inode changes (works in 4.0) 
Message-ID:  <200111212200.fALM02O99854@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/24955; it has been noted by GNATS.

From: Maxim Konovalov <maxim@macomnet.ru>
To: Ian Dowse <iedowse@maths.tcd.ie>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/24955:/usr/bin/tail -F in 4.1+ doesn't work if file inode
 changes (works in 4.0) 
Date: Thu, 22 Nov 2001 00:50:37 +0300 (MSK)

 Hello Ian,
 
 On Mon, 19 Nov 2001, Ian Dowse wrote:
 
 > In message <20011119214750.L60209-100000@news1.macomnet.ru>, Maxim Konovalov wr
 > ites:
 > >
 > >What about this one:
 >
 > Looks better, but unless I'm mistaken it introduces 250ms polling
 > even when -F is not specified; this would undo the benefit of using
 > kqueue in the first place.
 >
 > How about something like the modified version below? It only polls
 > in the -F case (with a longer 1s interval), and it separates the
 > choice of sleep vs kqueue from the stat calls necessary for -F.
 > We always use kqueue if supported, but in the -F case, the kqueue
 > timeout is set to 1 second. By keeping `kq' open, this patch also
 > allows switching back to kqueue, for example if a symlink is changed
 > so that the path moves from an NFS to a UFS filesystem.
 >
 > Note that the EVFILT_VNODE filter could probably be removed, since
 > it is no longer needed to notice when the file is renamed or deleted.
 
 Looks OK for me except one minor problem, see below
 
 > Ian
 >
 > Index: forward.c
 > ===================================================================
 > RCS file: /dump/FreeBSD-CVS/src/usr.bin/tail/forward.c,v
 > retrieving revision 1.27
 > diff -u -r1.27 forward.c
 > --- forward.c	1 Sep 2001 22:22:44 -0000	1.27
 > +++ forward.c	19 Nov 2001 22:34:00 -0000
 > @@ -94,10 +94,11 @@
 >  	off_t off;
 >  	struct stat *sbp;
 >  {
 > -	int ch, kq = -1;
 > +	int ch, n, kq = -1;
 >  	int action = USE_SLEEP;
 >  	struct kevent ev[2];
 >  	struct stat sb2;
 > +	struct timespec ts;
 >
 >  	switch(style) {
 >  	case FBYTES:
 > @@ -193,9 +194,10 @@
 >  		clearerr(fp);
 >
 >  		switch (action) {
 > -		case ADD_EVENTS: {
 > -			int n = 0;
 > -			struct timespec ts = { 0, 0 };
 > +		case ADD_EVENTS:
 > +			n = 0;
 > +			ts.tv_sec = 0;
 > +			ts.tv_nsec = 0;
 >
 >  			if (Fflag && fileno(fp) != STDIN_FILENO) {
 >  				EV_SET(&ev[n], fileno(fp), EVFILT_VNODE,
 > @@ -208,24 +210,27 @@
 >  			n++;
 >
 >  			if (kevent(kq, ev, n, NULL, 0, &ts) < 0) {
 > -				close(kq);
 > -				kq = -1;
 >  				action = USE_SLEEP;
 >  			} else {
 >  				action = USE_KQUEUE;
 >  			}
 >  			break;
 > -		}
 >
 >  		case USE_KQUEUE:
 > -			if (kevent(kq, NULL, 0, ev, 1, NULL) < 0)
 > +			ts.tv_sec = 1;
 > +			ts.tv_nsec = 0;
 > +			/*
 > +			 * In the -F case we set a timeout to ensure that
 > +			 * we re-stat the file at least once every second.
 > +			 */
 > +			n = kevent(kq, NULL, 0, ev, 1, Fflag ? &ts : NULL);
 > +			if (n < 0)
 >  				err(1, "kevent");
 > -
 > -			if (ev->filter == EVFILT_VNODE) {
 > -				/* file was rotated, wait until it reappears */
 > -				action = USE_SLEEP;
 > -			} else if (ev->data < 0) {
 > -				/* file shrank, reposition to end */
 > +			if (n == 0) {
 > +				/* timeout */
 > +				break;
 > +			} else if (ev->filter == EVFILT_READ && ev->data < 0) {
 > +				 /* file shrank, reposition to end */
 >  				if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
 >  					ierr();
 >  					return;
 > @@ -236,9 +241,11 @@
 >  		case USE_SLEEP:
 >                  	(void) usleep(250000);
 >  	                clearerr(fp);
 +                       if (kq != -1)
 +                               action = ADD_EVENTS;
 
 It will help to break USE_SLEEP cycle when you remove symlink to fname
 and recreate it again. Of course it will break automatically when new
 data arrives but it may never happen.
 
 > +			break;
 > +		}
 >
 > -			if (Fflag && fileno(fp) != STDIN_FILENO &&
 > -			    stat(fname, &sb2) != -1) {
 > +		if (Fflag && fileno(fp) != STDIN_FILENO) {
 > +			if (stat(fname, &sb2) != -1) {
 >  				if (sb2.st_ino != sbp->st_ino ||
 >  				    sb2.st_dev != sbp->st_dev ||
 >  				    sb2.st_rdev != sbp->st_rdev ||
 > @@ -246,16 +253,15 @@
 >  					fp = freopen(fname, "r", fp);
 >  					if (fp == NULL) {
 >  						ierr();
 > -						break;
 > -					}
 > -					*sbp = sb2;
 > -					if (kq != -1)
 > +					} else {
 > +						*sbp = sb2;
 >  						action = ADD_EVENTS;
 > -				} else if (kq != -1) {
 > -					action = USE_KQUEUE;
 > +					}
 >  				}
 > +			} else {
 > +				/* file was rotated, wait until it reappears */
 > +				action = USE_SLEEP;
 >  			}
 > -			break;
 >  		}
 >  	}
 >  }
 >
 >
 
 There is still an issue when fname is renamed. Our tail will continue
 read data from the renamed file in USE_SLEEP cycle until a new fname
 appear. The old tail (RELENG_4_0_0_RELEASE f.e.) works in the same
 way. Imho it is not a correct behaviour but I am not quite sure.
 
 -- 
 Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
 phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
 

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200111212200.fALM02O99854>