From d313a0b24234d3366ec263111469f219f5b4634f Mon Sep 17 00:00:00 2001 From: Stephane Chazelas Date: Tue, 3 Feb 2015 21:22:06 +0000 Subject: tail: fix -f to follow changes after a rename * src/tail.c (tail_forever_inotify): Only monitor write()s and truncate()s to files in --follow=descriptor mode, thus avoiding the bug where we removed the watch on renamed files. Also adjust the inotify event processing code that is now significant only in --follow=name mode. * tests/tail-2/F-vs-rename.sh: Improve this existing test by running in both polling and inotify modes. * tests/tail-2/f-vs-rename.sh: A new test based on the existing one. * tests/local.mk: Reference the new test. * NEWS: Mention the bug. Fixes http://bugs.gnu.org/19760 --- src/tail.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/tail.c b/src/tail.c index c5380cbe8..f75d7a9ee 100644 --- a/src/tail.c +++ b/src/tail.c @@ -159,13 +159,6 @@ struct File_spec uintmax_t n_unchanged_stats; }; -#if HAVE_INOTIFY -/* The events mask used with inotify on files. This mask is not used on - directories. */ -static const uint32_t inotify_wd_mask = (IN_MODIFY | IN_ATTRIB - | IN_DELETE_SELF | IN_MOVE_SELF); -#endif - /* Keep trying to open a file even if it is inaccessible when tail starts or if it becomes inaccessible later -- useful only with -f. */ static bool reopen_inaccessible_files; @@ -1390,6 +1383,13 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, if (! wd_to_name) xalloc_die (); + /* The events mask used with inotify on files (not directories). */ + uint32_t inotify_wd_mask = IN_MODIFY; + /* TODO: Perhaps monitor these events in Follow_descriptor mode also, + to tag reported file names with "deleted", "moved" etc. */ + if (follow_mode == Follow_name) + inotify_wd_mask |= (IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF); + /* Add an inotify watch for each watched file. If -F is specified then watch its parent directory too, in this way when they re-appear we can add them again to the watch list. */ @@ -1641,20 +1641,17 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, if (ev->mask & (IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF)) { - /* For IN_DELETE_SELF, we always want to remove the watch. - However, for IN_MOVE_SELF (the file we're watching has - been clobbered via a rename), when tailing by NAME, we - must continue to watch the file. It's only when following - by file descriptor that we must remove the watch. */ - if ((ev->mask & IN_DELETE_SELF) - || ((ev->mask & IN_MOVE_SELF) - && follow_mode == Follow_descriptor)) + /* Note for IN_MOVE_SELF (the file we're watching has + been clobbered via a rename) we leave the watch + in place since it may still be part of the set + of watched names. */ + if (ev->mask & IN_DELETE_SELF) { inotify_rm_watch (wd, fspec->wd); hash_delete (wd_to_name, fspec); } - if (follow_mode == Follow_name) - recheck (fspec, false); + + recheck (fspec, false); continue; } -- cgit v1.2.3-54-g00ecf