which was not the case when inotify was not available.
* src/tail.c (any_live_files): Simplify, since the IGNORE
flag is now only set when a file should be ignored indefinitely.
(recheck): Only output the "giving up on name" message
when that's actually the case. Only set the IGNORE flag
when ignoring a file indefinitely.
(tail_file): Likewise.
* tests/tail-2/retry.sh: Add a test case. Also run
all existing test cases with and without inotify.
NEWS: Mention the fix.
THANKS.in: Add the reporter.
Fixes http://bugs.gnu.org/24495 which was detected
using Symbolic Execution techniques developed in
the course of the SYMBIOSYS research project at
COMSYS, RWTH Aachen University.
seq now immediately exits upon write errors.
[This bug was present in "the beginning".]
+ tail -F now continues to process initially untailable files that are replaced
+ by a tailable file. This was handled correctly when inotify was available,
+ and is now handled correctly in all cases.
+ [bug introduced in fileutils-4.0h]
+
yes now handles short writes, rather than assuming all writes complete.
[bug introduced in coreutils-8.24]
Juan F. Codagnone juam@arnet.com.ar
Juan M. Guerrero st001906@hrz1.hrz.tu-darmstadt.de
Julian Bradfield jcb@inf.ed.ac.uk
+Julian Büning julian.buening@rwth-aachen.de
Jungshik Shin jshin@pantheon.yale.edu
Juraj Marko jmarko@redhat.com
Jürgen Fluk louis@dachau.marco.de
f->errnum = -1;
f->ignore = true;
- error (0, 0, _("%s has been replaced with a symbolic link. "
- "giving up on this name"), quoteaf (pretty_name (f)));
+ error (0, 0, _("%s has been replaced with an untailable symbolic link"),
+ quoteaf (pretty_name (f)));
}
else if (fd == -1 || fstat (fd, &new_stats) < 0)
{
{
ok = false;
f->errnum = -1;
- error (0, 0, _("%s has been replaced with an untailable file;\
- giving up on this name"),
- quoteaf (pretty_name (f)));
- f->ignore = true;
+ f->tailable = false;
+ if (! (reopen_inaccessible_files && follow_mode == Follow_name))
+ f->ignore = true;
+ if (was_tailable || prev_errnum != f->errnum)
+ error (0, 0, _("%s has been replaced with an untailable file%s"),
+ quoteaf (pretty_name (f)),
+ f->ignore ? _("; giving up on this name") : "");
}
else if (!disable_inotify && fremote (fd, pretty_name (f)))
{
ok = false;
f->errnum = -1;
- error (0, 0, _("%s has been replaced with a remote file. "
- "giving up on this name"), quoteaf (pretty_name (f)));
+ error (0, 0, _("%s has been replaced with an untailable remote file"),
+ quoteaf (pretty_name (f)));
f->ignore = true;
f->remote = true;
}
{
size_t i;
+ /* In inotify mode, ignore may be set for files
+ which may later be replaced with new files.
+ So always consider files live in -F mode. */
if (reopen_inaccessible_files && follow_mode == Follow_name)
- return true; /* continue following for -F option */
+ return true;
for (i = 0; i < n_files; i++)
{
if (0 <= f[i].fd)
- {
- return true;
- }
+ return true;
else
{
- if (reopen_inaccessible_files && follow_mode == Follow_descriptor)
- if (! f[i].ignore)
- return true;
+ if (! f[i].ignore && reopen_inaccessible_files)
+ return true;
}
}
}
else if (!IS_TAILABLE_FILE_TYPE (stats.st_mode))
{
- error (0, 0, _("%s: cannot follow end of this type of file;\
- giving up on this name"),
- quotef (pretty_name (f)));
ok = false;
f->errnum = -1;
- f->ignore = true;
+ f->tailable = false;
+ f->ignore = ! (reopen_inaccessible_files
+ && follow_mode == Follow_name);
+ error (0, 0, _("%s: cannot follow end of this type of file%s"),
+ quotef (pretty_name (f)),
+ f->ignore ? _("; giving up on this name") : "");
}
if (!ok)
[ "$(countlines_)" = 2 ] || { cat out; fail=1; }
grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
+for mode in '' '---disable-inotify'; do
+
# === Test:
# Ensure that "tail --retry --follow=name" waits for the file to appear.
# Clear 'out' so that we can check its contents without races
>out || framework_failure_
-timeout 10 tail $fastpoll --follow=name --retry missing >out 2>&1 & pid=$!
+timeout 10 \
+ tail $mode $fastpoll --follow=name --retry missing >out 2>&1 & pid=$!
# Wait for "cannot open" error.
retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
echo "X" > missing || framework_failure_
# === Test:
# Ensure that "tail --retry --follow=descriptor" waits for the file to appear.
# tail-8.21 failed at this (since the implementation of the inotify support).
-timeout 10 tail $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+timeout 10 \
+ tail $mode $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
# Wait for "cannot open" error.
retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
echo "X" > missing || framework_failure_
# === Test:
# Ensure that tail --follow=descriptor --retry exits when the file appears
# untailable. Expect exit status 1.
-timeout 10 tail $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
+timeout 10 \
+ tail $mode $fastpoll --follow=descriptor --retry missing >out 2>&1 & pid=$!
# Wait for "cannot open" error.
retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
mkdir missing || framework_failure_ # Create untailable
# Ensure that --follow=descriptor (without --retry) does *not wait* for the
# file to appear. Expect 2 lines in the output file ("cannot open" +
# "no files remaining") and exit status 1.
-tail --follow=descriptor missing >out 2>&1 && fail=1
+tail $mode --follow=descriptor missing >out 2>&1 && fail=1
[ "$(countlines_)" = 2 ] || { fail=1; cat out; }
grep -F 'cannot open' out || { fail=1; cat out; }
grep -F 'no files remaining' out || { fail=1; cat out; }
# === Test:
# Likewise for --follow=name (without --retry).
-tail --follow=name missing >out 2>&1 && fail=1
+tail $mode --follow=name missing >out 2>&1 && fail=1
[ "$(countlines_)" = 2 ] || { fail=1; cat out; }
grep -F 'cannot open' out || { fail=1; cat out; }
grep -F 'no files remaining' out || { fail=1; cat out; }
+# === Test:
+# Ensure that tail -F retries when the file is initally untailable.
+mkdir untailable
+timeout 10 \
+ tail $mode $fastpoll -F untailable >out 2>&1 & pid=$!
+# Wait for "cannot open" error.
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+{ rmdir untailable; echo foo > untailable; } || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+cleanup_
+[ "$(countlines_)" = 4 ] || { fail=1; cat out; }
+grep -F 'cannot follow' out || { fail=1; cat out; }
+grep -F 'has become accessible' out || { fail=1; cat out; }
+grep -F 'foo' out || { fail=1; cat out; }
+rm -fd untailable out || framework_failure_
+
+done
+
Exit $fail