Bug 24955

Summary: /usr/bin/tail -F in 4.1+ doesn't work if file inode changes (works in 4.0)
Product: Base System Reporter: kmarx <kmarx>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.2-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
tail.warns.diff none

Description kmarx 2001-02-08 19:30:01 UTC
There appears to be a difference in /usr/bin/tail -F between 4.0 and 4.1+.

It's not updating the inode it's doing the tail -F on when the inode changes.
(E.g., if you tail through a soft link and the link moves.)

This doesn't match the man page:

 -F      The -F option implies the -f option, but tail will also check to
         see if the file being followed has been renamed or rotated.  The 
         file is closed and reopened when tail detects that the filename
         being read from has a new inode number.  The -F option is ignored
         if reading from standard input rather than a file.

I just rebuilt a version from a 4.0 soure tree I have, and
that works. The difference is in /usr/src/usr.bin/tail/forward.c.
The one that doesn't work is: $FreeBSD: src/usr.bin/tail/forward.c,v 1.11.6.1 20
00/07/18 21:49:41 jlemon Exp $. The working 4.0 one has no cvs info.

I don't know if this is as it should be. A quick slog throught the
freebsd archies shows only a discussion of -f in CURRENT, and a reference
to a version of /usr/src/sys/kern/kern_event.c,v 1.14 that doesn't easily
compare to our 4.2 kern_event.c,v 1.2.2.4. Doesn't seem relevant...

I'll use my 4.0 version of tail, but thought someone might know
or care what the real deal is.

How-To-Repeat: 1. create file /tmp/poot1 containing:
     1  poot1
     2  poot1
     3  poot1
     4  poot1
     5  poot1
     6  poot1
     7  poot1
     8  poot1

2. creat file /tmp/poot2 containing:
     1  poot2
     2  poot2
     3  poot2
     4  poot2
     5  poot2
     6  poot2
     7  poot2
     8  poot2

3. Create a link to /tmp/poot1:

	ln -s /tmp/poot1 /tmp/pootlnk

4. In a separate shell, tail the link:

	tail -F /tmp/pootlnk

5. remove the link: rm /tmp/pootlnk

6. recreate the link pointing to the other file

	ln -s /tmp/poot2 /tmp/pootlnk

In 4.0 the tail -F will correctly show:

     1  poot1
     2  poot1
     3  poot1
     4  poot1
     5  poot1
     6  poot1
     7  poot1
     8  poot1
     1  poot2
     2  poot2
     3  poot2
     4  poot2
     5  poot2
     6  poot2
     7  poot2
     8  poot2

(And will continue to update correctly for any rm/ln sequence
when the new target of the link is != to the previous target)

In 4.1+ it will only show:

     1  poot1
     2  poot1
     3  poot1
     4  poot1
     5  poot1
     6  poot1
     7  poot1
     8  poot1
Comment 1 Maxim Konovalov 2001-11-03 08:43:33 UTC
Hello,

Try this patch:

Index: forward.c
===================================================================
RCS file: /home/ncvs/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	2 Nov 2001 21:46:27 -0000
@@ -94,10 +94,10 @@
 	off_t off;
 	struct stat *sbp;
 {
-	int ch, kq = -1;
+	int ch, dirfd, kq = -1;
 	int action = USE_SLEEP;
-	struct kevent ev[2];
-	struct stat sb2;
+	struct kevent ev[3];
+	struct stat sb2, sbl;

 	switch(style) {
 	case FBYTES:
@@ -179,6 +179,15 @@
 		action = ADD_EVENTS;
 	}

+	if (lstat(fname, &sbl) != -1) {
+		if ((sbl.st_mode & S_IFLNK) == S_IFLNK) {
+			dirfd = open((const char *)dirname(fname), O_RDONLY);
+			if (dirfd == -1)
+				err(1, "open");
+		}
+	} else
+		err(1, "lstat");
+
 	for (;;) {
 		while ((ch = getc(fp)) != EOF)
 			if (putchar(ch) == EOF)
@@ -202,6 +211,13 @@
 				    EV_ADD | EV_ENABLE | EV_CLEAR,
 				    NOTE_DELETE | NOTE_RENAME, 0, 0);
 				n++;
+
+				if ((sbl.st_mode & S_IFLNK) == S_IFLNK) {
+					EV_SET(&ev[n], dirfd, EVFILT_VNODE,
+					    EV_ADD | EV_ENABLE | EV_CLEAR,
+					    NOTE_WRITE, 0, 0);
+					n++;
+				}
 			}
 			EV_SET(&ev[n], fileno(fp), EVFILT_READ,
 			    EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0);

-- 
Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
Comment 2 iedowse 2001-11-19 01:39:04 UTC
In message <200111030850.fA38o2f55553@freefall.freebsd.org>, Maxim Konovalov wr
ites:
> Hello,
> 
> Try this patch:

Hi,

While this patch should address the particular case mentioned in this
PR (tail is pointed at a symlink, but the symlink changes), it doesn't
solve the general problem of any other component in the specified
path changing. Maybe it is best to just resort to a polling approach
when the '-F' flag is specified? It could still use kqueue, but just
re-stat the path every ~1-10 seconds to check if the inode changed.

Ian
Comment 3 Maxim Konovalov 2001-11-19 18:53:45 UTC
Hello,

On Sun, 18 Nov 2001, Ian Dowse wrote:

[...]
>  Hi,
>
>  While this patch should address the particular case mentioned in this
>  PR (tail is pointed at a symlink, but the symlink changes), it doesn't
>  solve the general problem of any other component in the specified
>  path changing. Maybe it is best to just resort to a polling approach
>  when the '-F' flag is specified? It could still use kqueue, but just
>  re-stat the path every ~1-10 seconds to check if the inode changed.

What about this one:

Index: forward.c
===================================================================
RCS file: /home/ncvs/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 18:31:49 -0000
@@ -180,6 +180,9 @@
 	}

 	for (;;) {
+		struct timespec ts;
+		int n;
+
 		while ((ch = getc(fp)) != EOF)
 			if (putchar(ch) == EOF)
 				oerr();
@@ -194,8 +197,9 @@

 		switch (action) {
 		case ADD_EVENTS: {
-			int n = 0;
-			struct timespec ts = { 0, 0 };
+			n = 0;
+			ts.tv_sec = 0;
+			ts.tv_nsec = 0;

 			if (Fflag && fileno(fp) != STDIN_FILENO) {
 				EV_SET(&ev[n], fileno(fp), EVFILT_VNODE,
@@ -218,10 +222,16 @@
 		}

 		case USE_KQUEUE:
-			if (kevent(kq, NULL, 0, ev, 1, NULL) < 0)
+			ts.tv_sec = 0;
+			ts.tv_nsec = 250000;
+
+			if ((n = kevent(kq, NULL, 0, ev, 1, &ts)) < 0)
 				err(1, "kevent");

-			if (ev->filter == EVFILT_VNODE) {
+			if (n == 0) {
+				/* timeout */
+				action = USE_SLEEP;
+			} else if (ev->filter == EVFILT_VNODE) {
 				/* file was rotated, wait until it reappears */
 				action = USE_SLEEP;
 			} else if (ev->data < 0) {
@@ -234,7 +244,7 @@
 			break;

 		case USE_SLEEP:
-                	(void) usleep(250000);
+                	(void)usleep(250000);
 	                clearerr(fp);

 			if (Fflag && fileno(fp) != STDIN_FILENO &&

>  Ian

- -maxim

-- 
Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
Comment 4 iedowse 2001-11-19 22:59:21 UTC
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.

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);
+			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;
 		}
 	}
 }
Comment 5 Maxim Konovalov 2001-11-21 21:50:37 UTC
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
Comment 6 iedowse 2001-11-22 00:39:28 UTC
In message <20011122002632.O38176-100000@news1.macomnet.ru>, Maxim Konovalov wr
ites:
>
>Looks OK for me except one minor problem, see below

Yes, I expect there are still a few rough edges :-)

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

True, I think I noticed this problem also. I originally had it
continuing to use kqueue while it was waiting for the file to
reappear (i.e. there was no "else action = USE_SLEEP" for the failed
stat case), but I was worried that in some cases the kevent() loop
might spin where the file had really gone away (e.g NFS, forcibly
unmounted filesystem etc). I guess another option would be to add
a while loop around the stat() containing a sleep(), e.g

	if (Fflag && ...) {
		while (stat(...) != 0)
			sleep(1);
		if (sb2.st_ino != sbp->st_ino || ...) {
			... freopen(...);
			action = ADD_EVENTS;
		}
	}

That would avoid a potential kevent() spin loop, and revert to the
nicer situation where `action' can only change between sleep and
kqueue via the ADD_EVENTS code. Any better suggestions welcome!

I noticed, BTW, that tail -F doesn't work reliably on NFS (I assume
it never did, and it is hard to fix). The problem is that stat()
can succeed even after the file has been deleted due to cacheing,
but as soon as you try to read, ESTALE is returned, so tail just
exits with an error.

Ian
Comment 7 Maxim Konovalov 2001-11-24 19:43:09 UTC
Hello Ian,

Here is the final patch. I attached a cumulative patch which includes
the changes below and changes for WARNS?=2.

Index: forward.c
===================================================================
RCS file: /home/ncvs/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	24 Nov 2001 19:06:28 -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,26 +241,25 @@
 		case USE_SLEEP:
                 	(void) usleep(250000);
 	                clearerr(fp);
+			break;
+		}

-			if (Fflag && fileno(fp) != STDIN_FILENO &&
-			    stat(fname, &sb2) != -1) {
-				if (sb2.st_ino != sbp->st_ino ||
-				    sb2.st_dev != sbp->st_dev ||
-				    sb2.st_rdev != sbp->st_rdev ||
-				    sb2.st_nlink == 0) {
-					fp = freopen(fname, "r", fp);
-					if (fp == NULL) {
-						ierr();
-						break;
-					}
+		if (Fflag && fileno(fp) != STDIN_FILENO) {
+			while (stat(fname, &sb2) != 0)
+				/* file was rotated, wait until it reappears */
+				(void)sleep(1);
+			if (sb2.st_ino != sbp->st_ino ||
+			    sb2.st_dev != sbp->st_dev ||
+			    sb2.st_rdev != sbp->st_rdev ||
+			    sb2.st_nlink == 0) {
+				fp = freopen(fname, "r", fp);
+				if (fp == NULL) {
+					ierr();
+				} else {
 					*sbp = sb2;
-					if (kq != -1)
-						action = ADD_EVENTS;
-				} else if (kq != -1) {
-					action = USE_KQUEUE;
+					action = ADD_EVENTS;
 				}
 			}
-			break;
 		}
 	}
 }

- -maxim

Comment 8 iedowse 2001-11-25 18:15:04 UTC
In message <20011124220954.I87876-200000@news1.macomnet.ru>, Maxim Konovalov wr
ites:
>Hello Ian,
>
>Here is the final patch.

Committed, thanks!

>I attached a cumulative patch which includes
>the changes below and changes for WARNS?=2.

Thanks, I'll commit this separately. I just had a glance at that patch,
and one thing I noticed was that where gcc complains about something
like

	while (c = *p++) {

it's better to take the opportunity to make the code more readable
rather than just adding brackets. e.g, change it to:

	while ((c = *p++) != '\0') {

Also, with constness warnings, try to avoid adding code to strdup
a string unless you actually need to modify it (e.g. make the
pointer const if possible). I didn't check the example carefully
though, so what you did may be the easiest way.

Ian
Comment 9 Maxim Konovalov 2001-11-25 20:14:03 UTC
Hello Ian,

WARNS?=2 patch:

Index: Makefile
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/Makefile,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 Makefile
--- Makefile	27 May 1994 12:32:45 -0000	1.1.1.1
+++ Makefile	25 Nov 2001 19:57:39 -0000
@@ -2,5 +2,6 @@

 PROG=	tail
 SRCS=	forward.c misc.c read.c reverse.c tail.c
+WARNS?=	2

 .include <bsd.prog.mk>
Index: extern.h
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/extern.h,v
retrieving revision 1.6
diff -u -r1.6 extern.h
--- extern.h	1 Sep 2001 22:22:44 -0000	1.6
+++ extern.h	25 Nov 2001 20:00:04 -0000
@@ -36,7 +36,7 @@
  */

 #define	WR(p, size) do { \
-	if (write(STDOUT_FILENO, p, size) != size) \
+	if (write(STDOUT_FILENO, p, size) != (ssize_t)size) \
 		oerr(); \
 	} while(0)

Index: forward.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/forward.c,v
retrieving revision 1.28
diff -u -r1.28 forward.c
--- forward.c	25 Nov 2001 18:03:28 -0000	1.28
+++ forward.c	25 Nov 2001 19:58:20 -0000
@@ -171,6 +171,9 @@
 			if (lines(fp, off))
 				return;
 		break;
+	case REVERSE:
+	case NOTSET:
+		break;
 	}

 	if (fflag) {
Index: read.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/read.c,v
retrieving revision 1.8
diff -u -r1.8 read.c
--- read.c	3 Dec 2000 17:05:45 -0000	1.8
+++ read.c	25 Nov 2001 20:00:26 -0000
@@ -115,7 +115,7 @@
 	} else {
 		if (wrap && (len = ep - p))
 			WR(p, len);
-		if (len = p - sp)
+		if ((len = p - sp) != 0)
 			WR(sp, len);
 	}
 	return 0;
@@ -140,15 +140,15 @@
 		u_int blen;
 		u_int len;
 		char *l;
-	} *lines;
+	} *slines;
 	int ch;
 	char *p;
 	int blen, cnt, recno, wrap;
 	char *sp;

-	if ((lines = malloc(off * sizeof(*lines))) == NULL)
+	if ((slines = malloc(off * sizeof(*slines))) == NULL)
 		err(1, "malloc");
-	bzero(lines, off * sizeof(*lines));
+	bzero(slines, off * sizeof(*slines));
 	sp = NULL;
 	blen = cnt = recno = wrap = 0;

@@ -160,13 +160,13 @@
 		}
 		*p++ = ch;
 		if (ch == '\n') {
-			if (lines[recno].blen < cnt) {
-				lines[recno].blen = cnt + 256;
-				if ((lines[recno].l = realloc(lines[recno].l,
-				    lines[recno].blen)) == NULL)
+			if (slines[recno].blen < (u_int)cnt) {
+				slines[recno].blen = cnt + 256;
+				if ((slines[recno].l = realloc(slines[recno].l,
+				    slines[recno].blen)) == NULL)
 					err(1, "realloc");
 			}
-			bcopy(sp, lines[recno].l, lines[recno].len = cnt);
+			bcopy(sp, slines[recno].l, slines[recno].len = cnt);
 			cnt = 0;
 			p = sp;
 			if (++recno == off) {
@@ -180,8 +180,8 @@
 		return 1;
 	}
 	if (cnt) {
-		lines[recno].l = sp;
-		lines[recno].len = cnt;
+		slines[recno].l = sp;
+		slines[recno].len = cnt;
 		if (++recno == off) {
 			wrap = 1;
 			recno = 0;
@@ -190,16 +190,16 @@

 	if (rflag) {
 		for (cnt = recno - 1; cnt >= 0; --cnt)
-			WR(lines[cnt].l, lines[cnt].len);
+			WR(slines[cnt].l, slines[cnt].len);
 		if (wrap)
 			for (cnt = off - 1; cnt >= recno; --cnt)
-				WR(lines[cnt].l, lines[cnt].len);
+				WR(slines[cnt].l, slines[cnt].len);
 	} else {
 		if (wrap)
 			for (cnt = recno; cnt < off; ++cnt)
-				WR(lines[cnt].l, lines[cnt].len);
+				WR(slines[cnt].l, slines[cnt].len);
 		for (cnt = 0; cnt < recno; ++cnt)
-			WR(lines[cnt].l, lines[cnt].len);
+			WR(slines[cnt].l, slines[cnt].len);
 	}
 	return 0;
 }
Index: reverse.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/reverse.c,v
retrieving revision 1.12
diff -u -r1.12 reverse.c
--- reverse.c	1 Sep 2001 22:22:44 -0000	1.12
+++ reverse.c	25 Nov 2001 20:00:51 -0000
@@ -101,6 +101,8 @@
 		case REVERSE:
 			r_buf(fp);
 			break;
+		case NOTSET:
+			break;
 		}
 }

Index: tail.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/tail/tail.c,v
retrieving revision 1.12
diff -u -r1.12 tail.c
--- tail.c	2 Oct 2001 06:22:01 -0000	1.12
+++ tail.c	25 Nov 2001 20:09:59 -0000
@@ -169,7 +169,7 @@
 	}

 	if (*argv)
-		for (first = 1; fname = *argv++;) {
+		for (first = 1; (fname = *argv++) != '\0';) {
 			if ((fp = fopen(fname, "r")) == NULL ||
 			    fstat(fileno(fp), &sb)) {
 				ierr();
@@ -189,7 +189,7 @@
 			(void)fclose(fp);
 		}
 	else {
-		fname = "stdin";
+		(const char *)fname = "stdin";

 		if (fstat(fileno(stdin), &sb)) {
 			ierr();
@@ -227,7 +227,7 @@
 	size_t len;
 	char *start;

-	while (ap = *++argv) {
+	while ((ap = *++argv) != '\0') {
 		/* Return if "--" or not an option of any form. */
 		if (ap[0] != '-') {
 			if (ap[0] != '+')
Comment 10 Maxim Konovalov 2002-01-19 17:05:24 UTC
Please close this PR, a fix was committed to -current and -stable.

-- 
Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
Comment 11 iedowse freebsd_committer freebsd_triage 2002-01-19 19:02:48 UTC
State Changed
From-To: open->closed


Fixed in both -current and -stable.