summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Voelker <mail@bernhard-voelker.de>2013-04-20 16:34:23 +0200
committerBernhard Voelker <mail@bernhard-voelker.de>2013-04-20 16:34:23 +0200
commit8f97679836d9d03b687cb854dbda52a8fbf9823f (patch)
tree8833d176bf264eed2caaa3c8123e81343025e7a1
parentd461bfd2743547360793acd2118d4c08ad7b84a8 (diff)
downloadcoreutils-8f97679836d9d03b687cb854dbda52a8fbf9823f.tar.xz
tail: exit following by descriptor when no tailable file left
As a side effect of the previous commit which fixes 'tail -f --retry' to wait for a file to appear, tail would not exit when the last file appears untailable and gives up on this file. This can happen, for example, when the argument file name appears as directory. Tail sets the 'ignore' flag of this file to true, but instead of exiting the program, tail would continue the loop. * src/tail.c (any_live_files): Change the function to return true if any of the files is still tailable or if tail should continue to try to check again. (tail_forever): Change the condition to break the loop in the "no files remaining" case, because now any_live_files() will care about it, as mentioned above. (parse_options): When --retry is used without any follow mode, then reset reopen_inaccessible_files to false. * tests/tail-2/retry.sh: Add test case.
-rw-r--r--src/tail.c31
-rw-r--r--tests/tail-2/retry.sh18
2 files changed, 43 insertions, 6 deletions
diff --git a/src/tail.c b/src/tail.c
index 373575705..6bbc7251f 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -1052,16 +1052,32 @@ recheck (struct File_spec *f, bool blocking)
}
/* Return true if any of the N_FILES files in F are live, i.e., have
- open file descriptors. */
+ open file descriptors, or should be checked again (see --retry).
+ When following descriptors, checking should only continue when any
+ of the files is not yet ignored. */
static bool
any_live_files (const struct File_spec *f, size_t n_files)
{
size_t i;
+ if (reopen_inaccessible_files && follow_mode == Follow_name)
+ return true; /* continue following for -F option */
+
for (i = 0; i < n_files; i++)
- if (0 <= f[i].fd)
- return true;
+ {
+ if (0 <= f[i].fd)
+ {
+ return true;
+ }
+ else
+ {
+ if (reopen_inaccessible_files && follow_mode == Follow_descriptor)
+ if (! f[i].ignore)
+ return true;
+ }
+ }
+
return false;
}
@@ -1189,7 +1205,7 @@ tail_forever (struct File_spec *f, size_t n_files, double sleep_interval)
f[i].size += bytes_read;
}
- if (! any_live_files (f, n_files) && ! reopen_inaccessible_files)
+ if (! any_live_files (f, n_files))
{
error (0, 0, _("no files remaining"));
break;
@@ -2031,8 +2047,11 @@ parse_options (int argc, char **argv,
if (reopen_inaccessible_files)
{
if (!forever)
- error (0, 0, _("warning: --retry ignored; --retry is useful"
- " only when following"));
+ {
+ reopen_inaccessible_files = false;
+ error (0, 0, _("warning: --retry ignored; --retry is useful"
+ " only when following"));
+ }
else if (follow_mode == Follow_descriptor)
error (0, 0, _("warning: --retry only effective for the initial open"));
}
diff --git a/tests/tail-2/retry.sh b/tests/tail-2/retry.sh
index 71d101556..d56d4c169 100644
--- a/tests/tail-2/retry.sh
+++ b/tests/tail-2/retry.sh
@@ -76,6 +76,24 @@ grep '^X$' out || { fail=1; cat out; }
rm -f missing out || fail=1
# === Test:
+# Ensure that tail --follow=descriptor --retry exits when the file appears
+# untailable. Expect exit status 1.
+timeout 10 tail -s.1 --follow=descriptor --retry missing >out 2>&1 & pid=$!
+retry_delay_ wait4lines_ .1 6 2 || fail=1 # Wait for "cannot open" error.
+mkdir missing || fail=1 # Create untailable 'missing'.
+retry_delay_ wait4lines_ .1 6 4 || fail=1 # Wait for the expected output.
+wait $pid
+rc=$?
+[ $( wc -l < out ) = 4 ] || { fail=1; cat out; }
+grep -F 'retry only effective for the initial open' out \
+ || { fail=1; cat out; }
+grep -F 'cannot open' out || { fail=1; cat out; }
+grep -F 'replaced with an untailable file' out || { fail=1; cat out; }
+grep -F 'no files remaining' out || { fail=1; cat out; }
+[ $rc = 1 ] || { fail=1; cat out; }
+rm -fd missing out || fail=1
+
+# === Test:
# 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.