Hi,

Since inotify is dereferencing the files it's told to watch (according to flags tail sets), the watched files should be dereferenced outside the inotify_* family of functions as well.
Example:
$ echo 1  > file
$ ln -sf file{,-link}
$ tail -F ./filelink > out 2>/dev/null
$ rm file
$ echo 2 > file
$ kill %1
$ cat out
results: out only contains the contents of "file" before it was deleted.
expected results: tail picks up on "file"'s reappearance.

To be precise, tail actually picks up on it. However, the list of watched files from inotify is a list of files after dereferencing, whereas tail compares it to the filenames of symlinks it got as arguments, resulting ofc in unhappy users.
Thanks,
Ondrej
>From 4b01b2dd1a8a2947f819240a6ea110637fd27464 Mon Sep 17 00:00:00 2001
From: Ondrej Oprala <[email protected]>
Date: Fri, 13 Sep 2013 17:31:24 +0200
Subject: [PATCH] tail: dereference watched files if possible

Previous behaviour failed to read contents of a reappearing file,
when symlinked by tail's watched file.

* NEWS: mention the change.
* src/tail.c (main): If arg is a symlink, save the name of the symlinked
file.
* tests/tail-2/symlink.sh: Exercise the changes.
* tests/local.mk: Add the test.
---
 NEWS                    |  4 ++++
 src/tail.c              | 11 +++++++++--
 tests/local.mk          |  3 ++-
 tests/tail-2/symlink.sh | 37 +++++++++++++++++++++++++++++++++++++
 4 files changed, 52 insertions(+), 3 deletions(-)
 create mode 100755 tests/tail-2/symlink.sh

diff --git a/NEWS b/NEWS
index d26722d..d2c9062 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,10 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
+  tail now dereferences watched files. Previously, having a symlink watched
+  by inotify, it didn't respond to the symlink target reappearing after being
+  deleted.
+
   df now processes the mount list correctly in the presence of unstatable
   mount points.  Previously it may have failed to output some mount points.
   [bug introduced in coreutils-8.21]
diff --git a/src/tail.c b/src/tail.c
index e7fefda..9b6cd09 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -43,6 +43,7 @@
 #include "stat-time.h"
 #include "xfreopen.h"
 #include "xnanosleep.h"
+#include "xreadlink.h"
 #include "xstrtol.h"
 #include "xstrtod.h"
 
@@ -2146,6 +2147,7 @@ main (int argc, char **argv)
     {
       n_files = argc - optind;
       file = argv + optind;
+
     }
   else
     {
@@ -2178,8 +2180,13 @@ main (int argc, char **argv)
     exit (EXIT_SUCCESS);
 
   F = xnmalloc (n_files, sizeof *F);
-  for (i = 0; i < n_files; i++)
-    F[i].name = file[i];
+  struct stat st;
+  for (i = 0; i < n_files; i++) {
+    if (!lstat(file[i], &st) && S_ISLNK(st.st_mode))
+        F[i].name = xreadlink(file[i]);
+    else
+        F[i].name = file[i];
+  }
 
   if (header_mode == always
       || (header_mode == multiple_files && n_files > 1))
diff --git a/tests/local.mk b/tests/local.mk
index b00ff59..d8a127c 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -391,7 +391,8 @@ all_tests =					\
   tests/misc/uniq-perf.sh			\
   tests/misc/xattr.sh				\
   tests/tail-2/wait.sh				\
-  tests/tail-2/retry.sh			\
+  tests/tail-2/retry.sh				\
+  tests/tail-2/symlink.sh				\
   tests/chmod/c-option.sh			\
   tests/chmod/equal-x.sh			\
   tests/chmod/equals.sh				\
diff --git a/tests/tail-2/symlink.sh b/tests/tail-2/symlink.sh
new file mode 100755
index 0000000..daf8815
--- /dev/null
+++ b/tests/tail-2/symlink.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Check if tail tracks it's files properly
+
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ tail
+
+fail=0
+
+echo 1 > file
+ln -sf file filelink
+
+#watch a symlink
+tail -F ./filelink > out 2>/dev/null &
+
+rm file
+echo 2 > file
+kill %1
+
+#does tail output the contents of a reappearing file?
+[ $(wc -l < out) = 2 ] || fail=1
+
+Exit $fail
-- 
1.8.3.1

Reply via email to