mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-20 18:56:39 +02:00
tail: -F now always processes initially untailable files
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.
This commit is contained in:
5
NEWS
5
NEWS
@@ -42,6 +42,11 @@ GNU coreutils NEWS -*- outline -*-
|
||||
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]
|
||||
|
||||
|
||||
@@ -330,6 +330,7 @@ Josselin Mouette joss@debian.org
|
||||
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
|
||||
|
||||
43
src/tail.c
43
src/tail.c
@@ -956,8 +956,8 @@ recheck (struct File_spec *f, bool blocking)
|
||||
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)
|
||||
{
|
||||
@@ -986,17 +986,20 @@ recheck (struct File_spec *f, bool blocking)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -1075,20 +1078,20 @@ any_live_files (const struct File_spec *f, size_t n_files)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1930,12 +1933,14 @@ tail_file (struct File_spec *f, uintmax_t n_units)
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -55,11 +55,14 @@ tail --retry missing > out 2>&1 && fail=1
|
||||
[ "$(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_
|
||||
@@ -76,7 +79,8 @@ rm -f missing out || 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_
|
||||
@@ -95,7 +99,8 @@ rm -f missing out || 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
|
||||
@@ -116,16 +121,35 @@ rm -fd missing out || framework_failure_
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user