]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
tail: ensure --follow=name unfollows renamed files
authorPádraig Brady <P@draigBrady.com>
Wed, 4 Dec 2024 19:40:55 +0000 (19:40 +0000)
committerPádraig Brady <P@draigBrady.com>
Thu, 5 Dec 2024 12:53:13 +0000 (12:53 +0000)
Require --retry to continue to track files upon rename.
We already unfollowed a file if it was renamed
to another file system (unlinked), so this makes the behavior
consistent if renaming to a file in the same file system.
I.e. --follow=name without --retry, means unfollow if the
name is unlinked or moved, so this change ensures that
behavior for all rename cases.
Related commits: v8.0-121-g3b997a9bcv8.23-161-gd313a0b24

* src/tail.c (tail_forever_notify): Remove watch for a renamed file
if --retry is not specified.
* tests/tail/F-vs-rename.sh: Related test cleanup.
* tests/tail/follow-name.sh: Add a test case.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/74653

NEWS
src/tail.c
tests/tail/F-vs-rename.sh
tests/tail/follow-name.sh

diff --git a/NEWS b/NEWS
index 5bd9199e435d75ff86b0c92da19026a128bad8a0..c1e604ffab00826f3b64cd1bcf7a790bd3770245 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   'shuf' generates more-random output when the output is small.
   [bug introduced in coreutils-8.6]
 
+  `tail --follow=name` no longer waits indefinitely for watched
+  file names that are moved elsewhere within the same file system.
+  [bug introduced in coreutils-8.24]
+
   'tail -c 4096 /dev/zero' no longer loops forever.
   [This bug was present in "the beginning".]
 
index 33acf9ab31afb100cac80229460b4d52725fe707..8cefb9c07a968ebd39c459752d2e0c54fa9a5a7a 100644 (file)
@@ -1812,10 +1812,11 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files,
       if (ev->mask & (IN_ATTRIB | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF))
         {
           /* Note for IN_MOVE_SELF (the file we're watching has
-             been clobbered via a rename) we leave the watch
+             been clobbered via a rename) without --retry we leave the watch
              in place since it may still be part of the set
              of watched names.  */
-          if (ev->mask & IN_DELETE_SELF)
+          if (ev->mask & IN_DELETE_SELF
+              || (!reopen_inaccessible_files && (ev->mask & IN_MOVE_SELF)))
             {
               inotify_rm_watch (wd, fspec->wd);
               hash_remove (wd_to_name, fspec);
index df2422985dcb06fe9e3a73a728e8a3c73658873d..2b66033b82ff54cacbdf0dc88cb6807a069478f9 100755 (executable)
@@ -63,26 +63,26 @@ for mode in '' '---disable-inotify'; do
     { cat out; fail=1; }
   # Wait up to 12.7s for "x" to be displayed:
   file='b' data='x' retry_delay_ check_tail_output .1 7 ||
-    { echo "$0: b: unexpected delay?"; cat out; fail=1; }
+    { echo "$0: b: unexpected delay 1?"; cat out; fail=1; }
 
   echo x2 > a
   # Wait up to 12.7s for this to appear in the output:
   # "tail: '...' has appeared;  following new file"
   tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
-    { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+    { echo "$0: a: unexpected delay 2?"; cat out; fail=1; }
   # Wait up to 12.7s for "x2" to be displayed:
   file='a' data='x2' retry_delay_ check_tail_output .1 7 ||
-    { echo "$0: a: unexpected delay 2?"; cat out; fail=1; }
+    { echo "$0: a: unexpected delay 3?"; cat out; fail=1; }
 
   echo y >> b
   # Wait up to 12.7s for "y" to appear in the output:
   file='b' data='y' retry_delay_ check_tail_output .1 7 ||
-    { echo "$0: b: unexpected delay 2?"; cat out; fail=1; }
+    { echo "$0: b: unexpected delay 4?"; cat out; fail=1; }
 
   echo z >> a
   # Wait up to 12.7s for "z" to appear in the output:
   file='a' data='z' retry_delay_ check_tail_output .1 7 ||
-    { echo "$0: a: unexpected delay 3?"; cat out; fail=1; }
+    { echo "$0: a: unexpected delay 5?"; cat out; fail=1; }
 
   cleanup_
 done
index 64864edfb1703e4d22f070525439a7ee498a6b55..f92839c9e77bd3c4959d2d2776dcb89394f91a93 100755 (executable)
@@ -23,13 +23,20 @@ cat <<\EOF > exp || framework_failure_
 tail: cannot open 'no-such' for reading: No such file or directory
 tail: no files remaining
 EOF
-
 returns_ 1 timeout 10 tail --follow=name no-such > out 2> err || fail=1
-
 # Remove an inconsequential inotify warning so
 # we can compare against the above error
 sed '/inotify cannot be used/d' err > k && mv k err
-
 compare exp err || fail=1
 
+# Between coreutils 8.34 and 9.5 inclusive, tail would have
+# waited indefinitely when a file was moved to the same file system
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+touch file || framework_failure_
+timeout 10 tail --follow=name file & pid=$!
+sleep .1 # Usually in inotify loop here
+mv file file.unfollow || framework_failure_
+wait $pid
+test $? = 1 || fail=1
+
 Exit $fail