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