summaryrefslogtreecommitdiff
path: root/tests/tail-2
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tail-2')
-rwxr-xr-xtests/tail-2/F-headers.sh59
-rwxr-xr-xtests/tail-2/F-vs-missing.sh51
-rwxr-xr-xtests/tail-2/F-vs-rename.sh104
-rwxr-xr-xtests/tail-2/append-only.sh13
-rwxr-xr-xtests/tail-2/assert-2.sh50
-rwxr-xr-xtests/tail-2/assert.sh55
-rwxr-xr-xtests/tail-2/big-4gb.sh2
-rwxr-xr-xtests/tail-2/descriptor-vs-rename.sh56
-rwxr-xr-xtests/tail-2/flush-initial.sh17
-rwxr-xr-xtests/tail-2/follow-name.sh2
-rwxr-xr-xtests/tail-2/follow-stdin.sh2
-rwxr-xr-xtests/tail-2/inotify-hash-abuse.sh56
-rwxr-xr-xtests/tail-2/inotify-hash-abuse2.sh33
-rwxr-xr-xtests/tail-2/inotify-race.sh55
-rwxr-xr-xtests/tail-2/inotify-race2.sh103
-rwxr-xr-xtests/tail-2/inotify-rotate-resources.sh108
-rwxr-xr-xtests/tail-2/inotify-rotate.sh73
-rwxr-xr-xtests/tail-2/pid.sh18
-rwxr-xr-xtests/tail-2/pipe-f.sh2
-rwxr-xr-xtests/tail-2/pipe-f2.sh18
-rwxr-xr-xtests/tail-2/proc-ksyms.sh2
-rwxr-xr-xtests/tail-2/retry.sh71
-rwxr-xr-xtests/tail-2/start-middle.sh2
-rwxr-xr-xtests/tail-2/symlink.sh54
-rwxr-xr-xtests/tail-2/tail-c.sh (renamed from tests/tail-2/infloop-1.sh)36
-rwxr-xr-xtests/tail-2/tail-n0f.sh12
-rwxr-xr-xtests/tail-2/truncate.sh56
-rwxr-xr-xtests/tail-2/wait.sh46
28 files changed, 829 insertions, 327 deletions
diff --git a/tests/tail-2/F-headers.sh b/tests/tail-2/F-headers.sh
new file mode 100755
index 00000000..31d0fa6b
--- /dev/null
+++ b/tests/tail-2/F-headers.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Ensure tail -F distinguishes output with the correct headers
+# Between coreutils 7.5 and 8.23 inclusive, 'tail -F ...' would
+# not output headers for or created/renamed files in certain cases.
+
+# Copyright (C) 2015 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
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a b out
+
+ tail $mode -F $fastpoll a b > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ tail_re="cannot open 'b'" retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ echo x > a
+ # Wait up to 12.7s for a's header to appear in the output:
+ tail_re='==> a <==' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+
+ echo y > b
+ # Wait up to 12.7s for b's header to appear in the output:
+ tail_re='==> b <==' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: b: unexpected delay?"; cat out; fail=1; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail-2/F-vs-missing.sh b/tests/tail-2/F-vs-missing.sh
index d47b3022..54fe30a8 100755
--- a/tests/tail-2/F-vs-missing.sh
+++ b/tests/tail-2/F-vs-missing.sh
@@ -3,7 +3,7 @@
# Before coreutils-8.6, tail -F missing/file would not
# notice any subsequent availability of the missing/file.
-# Copyright (C) 2010-2014 Free Software Foundation, Inc.
+# Copyright (C) 2010-2015 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
@@ -21,10 +21,6 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-debug='---disable-inotify'
-debug=
-tail $debug -F -s.1 missing/file > out 2>&1 & pid=$!
-
check_tail_output()
{
local delay="$1"
@@ -32,33 +28,32 @@ check_tail_output()
{ sleep $delay; return 1; }
}
-# Wait up to 6.3s for tail to start with diagnostic:
-# tail: cannot open 'missing/file' for reading: No such file or directory
-tail_re='cannot open' retry_delay_ check_tail_output .1 7 || fail=1
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-mkdir missing || fail=1
-(cd missing && echo x > file)
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-# Wait up to 6.3s for this to appear in the output:
-# "tail: '...' has appeared; following end of new file"
-tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
- { echo "$0: file: unexpected delay?"; cat out; fail=1; }
+for mode in '' '---disable-inotify'; do
+ rm -rf out missing
-kill -HUP $pid
+ tail $mode -F $fastpoll missing/file > out 2>&1 & pid=$!
-cleanup()
-{
- local delay="$1"
- rm -rf missing ||
- { sleep $delay; return 1; }
-}
+ # Wait up to 12.7s for tail to start with diagnostic:
+ # tail: cannot open 'missing/file' for reading: No such file or directory
+ tail_re='cannot open' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ mkdir missing || framework_failure_
+ (cd missing && echo x > file) || framework_failure_
+
+ # Wait up to 12.7s for this to appear in the output:
+ # "tail: '...' has appeared; following new file"
+ tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: file: unexpected delay?"; cat out; fail=1; }
+
+ cleanup_
+done
-# Try repeatedly to remove the temporary directory.
-# This is normally unnecessary, because the containing directory will
-# be removed by code from init.sh. However, when this particular test
-# is run on an NFS-mounted volume, sometimes init.sh's cleanup code
-# fails because the directory is not yet really empty, perhaps because
-# the tail process (reading missing/file) is not yet killed.
-retry_delay_ cleanup .1 6
Exit $fail
diff --git a/tests/tail-2/F-vs-rename.sh b/tests/tail-2/F-vs-rename.sh
index 3e31ec8c..06733fb4 100755
--- a/tests/tail-2/F-vs-rename.sh
+++ b/tests/tail-2/F-vs-rename.sh
@@ -1,9 +1,9 @@
#!/bin/sh
-# demonstrate that tail -F works when renaming the tailed files
-# Before coreutils-8.3, tail -F a b would stop tracking additions to b
-# after "mv a b".
+# Demonstrate that tail -F works when renaming the tailed files.
+# Between coreutils 7.5 and 8.2 inclusive, 'tail -F a b' would
+# stop tracking additions to b after 'mv a b'.
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -21,55 +21,63 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-touch a b || framework_failure_
-
-debug='---disable-inotify'
-debug=
-tail $debug -F -s.1 a b > out 2>&1 & pid=$!
-
check_tail_output()
{
local delay="$1"
- grep "$tail_re" out > /dev/null ||
- { sleep $delay; return 1; }
-}
-
-# Wait up to 6.3s for tail to start
-echo x > a
-tail_re='^x$' retry_delay_ check_tail_output .1 7 || fail=1
-
-mv a b || fail=1
-
-# Wait 6.3s for this diagnostic:
-# tail: 'a' has become inaccessible: No such file or directory
-tail_re='inaccessible' retry_delay_ check_tail_output .1 7 || fail=1
-
-echo x > a
-# Wait up to 6.3s for this to appear in the output:
-# "tail: '...' has appeared; following end of new file"
-tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
- { echo "$0: a: unexpected delay?"; cat out; fail=1; }
-
-echo y >> b
-# Wait up to 6.3s for "y" to appear in the output:
-tail_f_vs_rename_2() {
- local delay="$1"
- tr '\n' @ < out | grep '@@==> b <==@y@$' > /dev/null ||
- { sleep $delay; return 1; }
-}
-retry_delay_ tail_f_vs_rename_2 .1 7 ||
- { echo "$0: b: unexpected delay?"; cat out; fail=1; }
-
-echo z >> a
-# Wait up to 6.3s for "z" to appear in the output:
-tail_f_vs_rename_3() {
- local delay="$1"
- tr '\n' @ < out | grep '@@==> a <==@z@$' > /dev/null ||
+ grep "$tail_re" out ||
{ sleep $delay; return 1; }
}
-retry_delay_ tail_f_vs_rename_3 .1 7 ||
- { echo "$0: a: unexpected delay?"; cat out; fail=1; }
-kill -HUP $pid
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a b out
+ touch a b || framework_failure_
+
+ tail $mode -F $fastpoll a b > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ mv a b || framework_failure_
+
+ # Wait 12.7s for this diagnostic:
+ # tail: 'a' has become inaccessible: No such file or directory
+ tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ echo x > a
+ # Wait up to 12.7s for this to appear in the output:
+ # "tail: '...' has appeared; following new file"
+ tail_re='has appeared' retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+
+ echo y >> b
+ # Wait up to 12.7s for "y" to appear in the output:
+ tail_f_vs_rename_2() {
+ local delay="$1"
+ tr '\n' @ < out | grep '@@==> b <==@y@$' > /dev/null ||
+ { sleep $delay; return 1; }
+ }
+ retry_delay_ tail_f_vs_rename_2 .1 7 ||
+ { echo "$0: b: unexpected delay?"; cat out; fail=1; }
+
+ echo z >> a
+ # Wait up to 12.7s for "z" to appear in the output:
+ tail_f_vs_rename_3() {
+ local delay="$1"
+ tr '\n' @ < out | grep '@@==> a <==@z@$' > /dev/null ||
+ { sleep $delay; return 1; }
+ }
+ retry_delay_ tail_f_vs_rename_3 .1 7 ||
+ { echo "$0: a: unexpected delay?"; cat out; fail=1; }
+
+ cleanup_
+done
Exit $fail
diff --git a/tests/tail-2/append-only.sh b/tests/tail-2/append-only.sh
index 7414da3e..2ea5df1f 100755
--- a/tests/tail-2/append-only.sh
+++ b/tests/tail-2/append-only.sh
@@ -2,7 +2,7 @@
# Ensure that tail -f works on an append-only file
# Requires root access to do chattr +a, as well as an ext[23] or xfs file system
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2015 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
@@ -21,6 +21,9 @@
print_ver_ tail
require_root_
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
chattr_a_works=1
touch f
chattr +a f 2>/dev/null || chattr_a_works=0
@@ -32,10 +35,10 @@ if test $chattr_a_works = 0; then
fi
-for inotify in ---disable-inotify ''; do
- sleep 1 &
- pid=$!
- tail --pid=$pid -f $inotify f || fail=1
+for mode in '' '---disable-inotify'; do
+ sleep 1 & pid=$!
+ tail --pid=$pid -f $mode f || fail=1
+ cleanup_
done
chattr -a f 2>/dev/null
diff --git a/tests/tail-2/assert-2.sh b/tests/tail-2/assert-2.sh
index 930e422a..67804fea 100755
--- a/tests/tail-2/assert-2.sh
+++ b/tests/tail-2/assert-2.sh
@@ -1,9 +1,9 @@
#!/bin/sh
-# This variant of 'assert' would get a UMR reliably in 2.0.9.
+# This variant of 'assert' would get a Uninit Mem Read reliably in 2.0.9.
# Due to a race condition in the test, the 'assert' script would get
# the UMR on Solaris only some of the time, and not at all on Linux/GNU.
-# Copyright (C) 2000-2014 Free Software Foundation, Inc.
+# Copyright (C) 2000-2015 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
@@ -21,29 +21,37 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-# Not "expensive" per se, but sleeping for so long is annoying.
-very_expensive_
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
-ok='ok ok ok'
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-touch a
-tail --follow=name a foo > err 2>&1 &
-tail_pid=$!
-# Arrange for the tail process to die after 12 seconds.
-(sleep 12; kill $tail_pid) &
-echo $ok > f
-echo sleeping for 7 seconds...
-sleep 7
-mv f foo
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-# echo waiting....
-wait
+for mode in '' '---disable-inotify'; do
+ rm -f a foo out
+ touch a || framework_failure_
-case "$(cat err)" in
- *$ok) ;;
- *) fail=1;;
-esac
+ tail $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$!
-test $fail = 1 && cat err
+ # Wait up to 12.7s for tail to start.
+ echo x > a || framework_failure_
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
+
+ # Wait up to 12.7s for tail to notice new foo file
+ ok='ok ok ok'
+ echo "$ok" > foo || framework_failure_
+ tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: foo: unexpected delay?"; cat out; fail=1; break; }
+
+ cleanup_
+done
Exit $fail
diff --git a/tests/tail-2/assert.sh b/tests/tail-2/assert.sh
index 35a10da2..43bd1e14 100755
--- a/tests/tail-2/assert.sh
+++ b/tests/tail-2/assert.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Test for assertion failure in "test".
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2015 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
@@ -26,36 +26,43 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-# Not "expensive" per se, but sleeping for so long is annoying.
-very_expensive_
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
-ok='ok ok ok'
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-touch a foo
-tail --follow=name a foo > err 2>&1 &
-tail_pid=$!
-# Arrange for the tail process to die after 12 seconds.
-(sleep 12; kill $tail_pid) &
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-echo sleeping for 7 seconds...
+for mode in '' '---disable-inotify'; do
+ rm -f a foo out
+ touch a foo || framework_failure_
-# Give the backgrounded 'tail' a chance to start before removing foo.
-# Otherwise, without --retry, tail wouldn't try to open 'foo' again.
-sleep 1
+ tail $mode --follow=name $fastpoll a foo > out 2>&1 & pid=$!
-rm -f foo
-sleep 6
-echo $ok > f
-mv f foo
+ # Wait up to 12.7s for tail to start.
+ echo x > a || framework_failure_
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
-# echo waiting....
-wait
+ # Wait 12.7s for this diagnostic:
+ # tail: foo: No such file or directory
+ rm foo || framework_failure_
+ tail_re='No such file' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; break; }
-case "$(cat err)" in
- *$ok) ;;
- *) fail=1;;
-esac
+ # Wait up to 12.7s for tail to notice new foo file
+ ok='ok ok ok'
+ echo "$ok" > foo || framework_failure_
+ tail_re="^$ok$" retry_delay_ check_tail_output .1 7 ||
+ { echo "$0: foo: unexpected delay?"; cat out; fail=1; break; }
-test $fail = 1 && cat err
+ cleanup_
+done
Exit $fail
diff --git a/tests/tail-2/big-4gb.sh b/tests/tail-2/big-4gb.sh
index cfd867b7..ac07a022 100755
--- a/tests/tail-2/big-4gb.sh
+++ b/tests/tail-2/big-4gb.sh
@@ -2,7 +2,7 @@
# Demonstrate a bug in 'tail -cN' when operating on files of size 4G and larger
# Fixed in coreutils-4.5.2.
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2015 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
diff --git a/tests/tail-2/descriptor-vs-rename.sh b/tests/tail-2/descriptor-vs-rename.sh
new file mode 100755
index 00000000..083d7144
--- /dev/null
+++ b/tests/tail-2/descriptor-vs-rename.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Demonstrate that tail -f works when renaming the tailed files.
+# Between coreutils 7.5 and 8.23 inclusive, 'tail -f a' would
+# stop tracking additions to b after 'mv a b'.
+
+# Copyright (C) 2015 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
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for mode in '' '---disable-inotify'; do
+ rm -f a out
+ touch a || framework_failure_
+
+ tail $mode $fastpoll -f a > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start.
+ echo x > a
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ mv a b || framework_failure_
+
+ echo y >> b
+ # Wait up to 12.7s for "y" to appear in the output:
+ tail_re='^y$' retry_delay_ check_tail_output .1 7 || { cat out; fail=1; }
+
+ cleanup_
+done
+
+Exit $fail
diff --git a/tests/tail-2/flush-initial.sh b/tests/tail-2/flush-initial.sh
index fd14eae9..a25bbeb1 100755
--- a/tests/tail-2/flush-initial.sh
+++ b/tests/tail-2/flush-initial.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# inotify-based tail -f didn't flush its initial output before blocking
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -19,13 +19,18 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-echo line > in || fail=1
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+echo line > in || framework_failure_
# Output should be buffered since we're writing to file
# so we're depending on the flush to write out
-tail -f in > out &
-tail_pid=$!
+tail $fastpoll -f in > out & pid=$!
-# Wait for 1.5s for the file to be flushed.
+# Wait for 3.1s for the file to be flushed.
tail_flush()
{
local delay="$1"
@@ -35,6 +40,6 @@ tail_flush()
}
retry_delay_ tail_flush .1 5 || fail=1
-kill $tail_pid
+cleanup_
Exit $fail
diff --git a/tests/tail-2/follow-name.sh b/tests/tail-2/follow-name.sh
index f70baec3..be68479e 100755
--- a/tests/tail-2/follow-name.sh
+++ b/tests/tail-2/follow-name.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# ensure that --follow=name does not imply --retry
-# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+# Copyright (C) 2011-2015 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
diff --git a/tests/tail-2/follow-stdin.sh b/tests/tail-2/follow-stdin.sh
index 1769ee2c..f50dd726 100755
--- a/tests/tail-2/follow-stdin.sh
+++ b/tests/tail-2/follow-stdin.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# tail -f - would fail with the initial inotify implementation
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
diff --git a/tests/tail-2/inotify-hash-abuse.sh b/tests/tail-2/inotify-hash-abuse.sh
index 6492049d..6333699c 100755
--- a/tests/tail-2/inotify-hash-abuse.sh
+++ b/tests/tail-2/inotify-hash-abuse.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Exercise an abort-inducing flaw in inotify-enabled tail -F.
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -23,10 +23,6 @@ print_ver_ tail
n=9
seq $n | xargs touch || framework_failure_
-debug='---disable-inotify'
-debug=
-tail $debug -s.1 -qF $(seq $n) > out 2>&1 & pid=$!
-
check_tail_output()
{
local delay="$1"
@@ -34,30 +30,42 @@ check_tail_output()
{ sleep $delay; return 1; }
}
-# Wait up to 6.3s for tail to start
-echo x > $n
-tail_re='^x$' retry_delay_ check_tail_output .1 7 || fail=1
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-mv 1 f || fail=1
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-# Wait 6.3s for this diagnostic:
-# tail: '1' has become inaccessible: No such file or directory
-tail_re='inaccessible' retry_delay_ check_tail_output .1 7 || fail=1
+for mode in '' '---disable-inotify'; do
+ rm -f out
-# Trigger the bug. Before the fix, this would provoke the abort.
-echo a > 1 || fail=1
+ tail $mode $fastpoll -qF $(seq $n) > out 2>&1 & pid=$!
-# Wait up to 2s for the buggy tail to die,
-# or for the "tail: '1' has appeared; following end of new file" output
-for i in $(seq 10); do
- kill -0 $pid || break
- grep 'has appeared;' out > /dev/null && break
- sleep .2
-done
+ # Wait up to 12.7s for tail to start
+ echo x > $n
+ tail_re='^x$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ mv 1 f || framework_failure_
+
+ # Wait 12.7s for this diagnostic:
+ # tail: '1' has become inaccessible: No such file or directory
+ tail_re='inaccessible' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
-# Kill the working tail, or fail if it has already aborted
-kill $pid || fail=1
+ # Trigger the bug. Before the fix, this would provoke the abort.
+ echo a > 1 || framework_failure_
+
+ # Wait up to 6.3s for the "tail: '1' has appeared; ..." message
+ # (or for the buggy tail to die)
+ tail_re='has appeared' retry_delay_ check_tail_output .1 6 ||
+ { cat out; fail=1; }
+
+ # Double check that tail hasn't aborted
+ kill -0 $pid || fail=1
+
+ cleanup_
+done
-cat out
Exit $fail
diff --git a/tests/tail-2/inotify-hash-abuse2.sh b/tests/tail-2/inotify-hash-abuse2.sh
index 6018448f..d641c241 100755
--- a/tests/tail-2/inotify-hash-abuse2.sh
+++ b/tests/tail-2/inotify-hash-abuse2.sh
@@ -2,7 +2,7 @@
# Exercise an abort-inducing flaw in inotify-enabled tail -F.
# Like inotify-hash-abuse, but without a hard-coded "9".
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -20,20 +20,27 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-touch f || framework_failure_
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-debug='---disable-inotify -s .001'
-debug=
-tail $debug -F f & pid=$!
-cleanup_() { kill $pid; }
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-for i in $(seq 200); do
- kill -0 $pid || break;
- mv f g
- touch f
-done
+for mode in '' '---disable-inotify'; do
+ touch f || framework_failure_
+
+ tail $mode $fastpoll -F f & pid=$!
+
+ for i in $(seq 200); do
+ kill -0 $pid || break;
+ mv f g
+ touch f
+ done
-# Kill the working tail, or fail if it has already aborted
-kill $pid || fail=1
+ # Ensure tail hasn't aborted
+ kill -0 $pid || fail=1
+
+ cleanup_
+done
Exit $fail
diff --git a/tests/tail-2/inotify-race.sh b/tests/tail-2/inotify-race.sh
index c25f354a..4ce05083 100755
--- a/tests/tail-2/inotify-race.sh
+++ b/tests/tail-2/inotify-race.sh
@@ -5,7 +5,7 @@
# indefinitely if no *other* data is appended, but it would be printed as
# soon as any additional appended data is detected.
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -23,10 +23,11 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-# Don't run this test by default because sometimes it's skipped as noted below.
-# Also gdb has a bug in Debian's gdb-6.8-3 at least that causes it to not
-# cleanup and exit correctly when it receives a SIGTERM, thus hanging the test.
-very_expensive_
+# Terminate any background gdb/tail process
+cleanup_() {
+ kill $pid 2>/dev/null && wait $pid
+ kill $sleep 2>/dev/null && wait $sleep
+}
touch file || framework_failure_
touch tail.out || framework_failure_
@@ -37,37 +38,61 @@ case $(cat gdb.out) in
*) skip_ "can't run gdb";;
esac
-break_src="$abs_top_builddir/src/tail.c"
+# Break on a line rather than a symbol, to cater for inline functions
+break_src="$abs_top_srcdir/src/tail.c"
break_line=$(grep -n ^tail_forever_inotify "$break_src") || framework_failure_
break_line=$(echo "$break_line" | cut -d: -f1) || framework_failure_
+
+# Note we get tail to monitor a background sleep process
+# rather than using timeout(1), as timeout sends SIGCONT
+# signals to its monitored process, and gdb (7.9 at least)
+# has _intermittent_ issues with this.
+# Sending SIGCONT resulted in either delayed child termination,
+# or no child termination resulting in a hung test.
+# See https://sourceware.org/bugzilla/show_bug.cgi?id=18364
+
+env sleep 10 & sleep=$!
+
# See if gdb works and
# tail_forever_inotify is compiled and run
-timeout 10s gdb -nx --batch-silent \
+gdb -nx --batch-silent \
--eval-command="break $break_line" \
- --eval-command='run -f file' \
+ --eval-command="run --pid=$sleep -f file" \
--eval-command='quit' \
- tail < /dev/null > gdb.out 2>&1 || skip_ 'breakpoint not hit'
+ tail < /dev/null > gdb.out 2>&1
+
+kill $sleep || skip_ 'breakpoint not hit'
+wait $sleep
# FIXME: The above is seen to _intermittently_ fail with:
# warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
# warning: difference appears to be caused by prelink, adjusting expectations
compare /dev/null gdb.out || skip_ "can't set breakpoints in tail"
+env sleep 10 & sleep=$!
+
# Run "tail -f file", stopping to append a line just before
# inotify initialization, and then continue. Before the fix,
# that just-appended line would never be output.
-timeout 10s gdb -nx --batch-silent \
+gdb -nx --batch-silent \
--eval-command="break $break_line" \
- --eval-command='run -f file >> tail.out' \
+ --eval-command="run --pid=$sleep -f file >> tail.out" \
--eval-command='shell echo never-seen-with-tail-7.5 >> file' \
--eval-command='continue' \
--eval-command='quit' \
- tail < /dev/null > /dev/null 2>&1 &
-pid=$!
+ tail < /dev/null > /dev/null 2>&1 & pid=$!
+
+tail --pid=$pid -f tail.out | (read REPLY; kill $pid)
+
+# gdb has a bug in Debian's gdb-6.8-3 at least that causes it to not
+# cleanup and exit correctly when it receives a SIGTERM, but
+# killing sleep, should cause the tail process and thus gdb to exit.
+kill $sleep
+wait $sleep
-tail --pid=$pid -f tail.out | (read; kill $pid)
+wait $pid
-test -s tail.out || fail=1
+compare /dev/null tail.out && fail=1
Exit $fail
diff --git a/tests/tail-2/inotify-race2.sh b/tests/tail-2/inotify-race2.sh
new file mode 100755
index 00000000..1e01d505
--- /dev/null
+++ b/tests/tail-2/inotify-race2.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Ensure that tail does not ignore a tailed-forever file that has been
+# replaced between tail's initial read-to-EOF, and when the inotify watches
+# are established in tail_forever_inotify. That new file would be ignored
+# indefinitely.
+
+# Copyright (C) 2015 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
+
+# Terminate any background gdb/tail process
+cleanup_() {
+ kill $pid 2>/dev/null && wait $pid
+ kill $sleep 2>/dev/null && wait $sleep
+}
+
+touch file || framework_failure_
+touch tail.out || framework_failure_
+
+( timeout 10s gdb --version ) > gdb.out 2>&1
+case $(cat gdb.out) in
+ *'GNU gdb'*) ;;
+ *) skip_ "can't run gdb";;
+esac
+
+# Break on a line rather than a symbol, to cater for inline functions
+break_src="$abs_top_srcdir/src/tail.c"
+break_line=$(grep -n ^tail_forever_inotify "$break_src") || framework_failure_
+break_line=$(echo "$break_line" | cut -d: -f1) || framework_failure_
+
+
+# Note we get tail to monitor a background sleep process
+# rather than using timeout(1), as timeout sends SIGCONT
+# signals to its monitored process, and gdb (7.9 at least)
+# has _intermittent_ issues with this.
+# Sending SIGCONT resulted in either delayed child termination,
+# or no child termination resulting in a hung test.
+# See https://sourceware.org/bugzilla/show_bug.cgi?id=18364
+
+env sleep 10 & sleep=$!
+
+# See if gdb works and
+# tail_forever_inotify is compiled and run
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -f file" \
+ --eval-command='quit' \
+ tail < /dev/null > gdb.out 2>&1
+
+kill $sleep || skip_ 'breakpoint not hit'
+wait $sleep
+
+# FIXME: The above is seen to _intermittently_ fail with:
+# warning: .dynamic section for "/lib/libc.so.6" is not at the expected address
+# warning: difference appears to be caused by prelink, adjusting expectations
+compare /dev/null gdb.out || skip_ "can't set breakpoints in tail"
+
+env sleep 10 & sleep=$!
+
+echo never-seen-with-tail-8.23 > file.new || framework_failure_
+
+# Run "tail -F file", stopping to replace with a new file before
+# inotify initialization, and then continue. Before the fix,
+# changes to the new file would effectively be ignored.
+gdb -nx --batch-silent \
+ --eval-command="break $break_line" \
+ --eval-command="run --pid=$sleep -F file 2>tail.err >>tail.out" \
+ --eval-command='shell mv file.new file' \
+ --eval-command='continue' \
+ --eval-command='quit' \
+ tail < /dev/null > /dev/null 2>&1 & pid=$!
+
+# Note even updating the watched 'file' wouldn't have output
+# anything between coreutils 7.5 and 8.23 inclusive as
+# The old file descriptor (still held open by tail) was being fstat().
+
+tail --pid=$pid -f tail.out | (read REPLY; kill $pid)
+
+# gdb has a bug in Debian's gdb-6.8-3 at least that causes it to not
+# cleanup and exit correctly when it receives a SIGTERM, but
+# killing sleep, should cause the tail process and thus gdb to exit.
+kill $sleep
+wait $sleep
+
+wait $pid
+
+compare /dev/null tail.out && { cat tail.err; fail=1; }
+
+Exit $fail
diff --git a/tests/tail-2/inotify-rotate-resources.sh b/tests/tail-2/inotify-rotate-resources.sh
new file mode 100755
index 00000000..fe5d9127
--- /dev/null
+++ b/tests/tail-2/inotify-rotate-resources.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+# ensure that tail -F doesn't leak inotify resources
+
+# Copyright (C) 2015 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
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ || skip_ 'inotify required'
+
+require_strace_ 'inotify_add_watch,inotify_rm_watch'
+
+# Quickly skip on remote file systems
+is_local_dir_ . || skip_ 'inotify not used on remote file system'
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Wait up to 25.5 seconds for grep REGEXP 'out' to succeed.
+grep_timeout() { tail_re="$1" retry_delay_ check_tail_output .1 8; }
+
+check_strace()
+{
+ local delay="$1"
+ grep "$strace_re" strace.out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+cleanup_fail()
+{
+ cat out
+ warn_ $1
+ fail=1
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+touch k || framework_failure_
+
+# Note the timeout guard isn't strictly necessary here,
+# however without it strace will ignore SIGTERM.
+# strace does always honor SIGTERM with the -I2 option,
+# though that's not available on RHEL6 for example.
+timeout 180 strace -e inotify_add_watch,inotify_rm_watch -o strace.out \
+ tail -F $fastpoll k >> out 2>&1 & pid=$!
+
+reverted_to_polling_=0
+for i in $(seq 2); do
+ echo $i
+
+ echo 'tailed' > k;
+
+ # Wait for watch on (new) file
+ strace_re='inotify_add_watch.*MODIFY' retry_delay_ check_strace .1 8 ||
+ no_watch_=1
+
+ # Assume this is not because we're leaking
+ # (resources may already be depleted)
+ # The explicit check for inotify_rm_watch should confirm that.
+ grep -F 'reverting to polling' out >/dev/null && skip_ 'inotify unused'
+
+ # Otherwise failure is unknown
+ test "$no_watch_" && { cat out; framework_failure_ 'no inotify_add_watch'; }
+
+ mv k k.tmp
+ # wait for tail to detect the rename
+ grep_timeout 'inaccessible' ||
+ { cleanup_fail 'failed to detect rename'; break; }
+
+ # Note we strace here rather than consuming all available watches
+ # to be more efficient, but more importantly avoid depleting resources.
+ # Note also available resources can currently be tuned with:
+ # sudo sysctl -w fs.inotify.max_user_watches=$smallish_number
+ # However that impacts all processes for the current user, and also
+ # may not be supported in future, instead being auto scaled to RAM
+ # like the Linux epoll resources were.
+ if test "$i" -gt 1; then
+ strace_re='inotify_rm_watch' retry_delay_ check_strace .1 8 ||
+ { cleanup_fail 'failed to find inotify_rm_watch syscall'; break; }
+ fi
+
+ >out && >strace.out || framework_failure_ 'failed to reset output files'
+done
+
+cleanup_
+
+Exit $fail
diff --git a/tests/tail-2/inotify-rotate.sh b/tests/tail-2/inotify-rotate.sh
index 1c942cc3..638a3bbb 100755
--- a/tests/tail-2/inotify-rotate.sh
+++ b/tests/tail-2/inotify-rotate.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# ensure that tail -F handles rotation
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -16,55 +16,62 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if test "$VERBOSE" = yes; then
- set -x
- tail --version
-fi
-
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
-expensive_
+print_ver_ tail
+
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ || expensive_
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Wait up to 25.5 seconds for grep REGEXP 'out' to succeed.
+grep_timeout() { tail_re="$1" retry_delay_ check_tail_output .1 8; }
-# Wait several seconds for grep REGEXP FILE to succeed.
-# Usage: grep_timeout REGEXP FILE
-grep_timeout()
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+cleanup_fail()
{
- local j
- for j in $(seq 150); do
- grep $1 $2 > /dev/null && return 0
- sleep 0.1
- done
- return 1
+ cat out
+ warn_ $1
+ cleanup_
+ fail=1
}
-# For details, see
-# http://lists.gnu.org/archive/html/bug-coreutils/2009-11/msg00213.html
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
# Perform at least this many iterations, because on multi-core systems
# the offending sequence of events can be surprisingly uncommon.
+# See: http://lists.gnu.org/archive/html/bug-coreutils/2009-11/msg00213.html
for i in $(seq 50); do
echo $i
- rm -rf k x out
+ rm -f k x out
+
# Normally less than a second is required here, but with heavy load
# and a lot of disk activity, even 20 seconds is insufficient, which
# leads to this timeout killing tail before the "ok" is written below.
>k && >x || framework_failure_ failed to initialize files
- timeout 40 tail -F k > out 2>&1 &
- pid=$!
- sleep .1
- echo b > k;
- # wait for b to appear in out
- grep_timeout b out || fail_ failed to find b in out
- while :; do grep b out > /dev/null && break; done
+ timeout 60 tail $fastpoll -F k > out 2>&1 & pid=$!
+
+ echo 'tailed' > k;
+ # wait for 'tailed' to appear in out
+ grep_timeout 'tailed' || { cleanup_fail 'failed to find "tailed"'; break; }
+
mv x k
# wait for tail to detect the rename
- grep_timeout tail: out || { cat out; fail_ failed to detect rename; }
+ grep_timeout 'tail:' || { cleanup_fail 'failed to detect rename'; break; }
+
echo ok >> k
- found=0
- # wait up to 10 seconds for "ok" to appear in out
- grep_timeout ok out && found=1
- kill $pid
- test $found = 0 && { cat out; fail_ failed to detect echoed '"ok"'; }
+ # wait for "ok" to appear in 'out'
+ grep_timeout 'ok' || { cleanup_fail 'failed to detect echoed ok'; break; }
+
+ cleanup_
done
-wait
Exit $fail
diff --git a/tests/tail-2/pid.sh b/tests/tail-2/pid.sh
index ef440818..b410478e 100755
--- a/tests/tail-2/pid.sh
+++ b/tests/tail-2/pid.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Test the --pid option of tail.
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2015 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
@@ -22,29 +22,29 @@ getlimits_
touch empty here || framework_failure_
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
-for inotify in ---disable-inotify ''; do
+for mode in '' '---disable-inotify'; do
# Use tail itself to create a background process to monitor,
# which will auto exit when "here" is removed.
- tail -f $inotify here &
- bg_pid=$!
+ tail -f $mode here & pid=$!
# Ensure that tail --pid=PID does not exit when PID is alive.
- timeout 1 tail -f -s.1 --pid=$bg_pid $inotify here
+ timeout 1 tail -f -s.1 --pid=$pid $mode here
test $? = 124 || fail=1
- # Cleanup background process
- kill $bg_pid
+ cleanup_
# Ensure that tail --pid=PID exits with success status when PID is dead.
# Use an unlikely-to-be-live PID
- timeout 10 tail -f -s.1 --pid=$PID_T_MAX $inotify empty
+ timeout 10 tail -f -s.1 --pid=$PID_T_MAX $mode empty
ret=$?
test $ret = 124 && skip_ "pid $PID_T_MAX present or tail too slow"
test $ret = 0 || fail=1
# Ensure tail doesn't wait for data when PID is dead
- timeout 10 tail -f -s10 --pid=$PID_T_MAX $inotify empty
+ timeout 10 tail -f -s10 --pid=$PID_T_MAX $mode empty
test $? = 124 && fail=1
done
diff --git a/tests/tail-2/pipe-f.sh b/tests/tail-2/pipe-f.sh
index eaa928fb..22850c49 100755
--- a/tests/tail-2/pipe-f.sh
+++ b/tests/tail-2/pipe-f.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# ensure that :|tail -f doesn't hang, per POSIX
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
diff --git a/tests/tail-2/pipe-f2.sh b/tests/tail-2/pipe-f2.sh
index 13ccd0b3..71a081c3 100755
--- a/tests/tail-2/pipe-f2.sh
+++ b/tests/tail-2/pipe-f2.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Ensure that "tail -f fifo" tails indefinitely.
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2015 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
@@ -24,7 +24,13 @@ mkfifo_or_skip_ fifo
echo 1 > fifo &
echo 1 > exp || framework_failure_
-timeout 10 tail -f fifo > out & pid=$!
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+timeout 10 tail $fastpoll -f fifo > out & pid=$!
check_tail_output()
{
@@ -32,12 +38,14 @@ check_tail_output()
test -s out || { sleep $n_sec; return 1; }
}
-# Wait 6.3s for tail to write something.
+# Wait 12.7s for tail to write something.
retry_delay_ check_tail_output .1 7 || fail=1
compare exp out || fail=1
-# Kill the still-running tail, or fail if it's gone.
-kill $pid || fail=1
+# Ensure tail is still running
+kill -0 $pid || fail=1
+
+cleanup_
Exit $fail
diff --git a/tests/tail-2/proc-ksyms.sh b/tests/tail-2/proc-ksyms.sh
index 3f799649..cd007744 100755
--- a/tests/tail-2/proc-ksyms.sh
+++ b/tests/tail-2/proc-ksyms.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Prior to textutils-2.0.17, 'tail /proc/ksyms' would segfault on Linux.
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2015 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
diff --git a/tests/tail-2/retry.sh b/tests/tail-2/retry.sh
index dbe66a4e..a1497d90 100755
--- a/tests/tail-2/retry.sh
+++ b/tests/tail-2/retry.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Exercise tail's behavior regarding missing files with/without --retry.
-# Copyright (C) 2013-2014 Free Software Foundation, Inc.
+# Copyright (C) 2013-2015 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
@@ -19,6 +19,13 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
+# Function to count number of lines from tail
+# while ignoring transient errors due to resource limits
+countlines_ ()
+{
+ grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
+}
+
# Function to check the expected line count in 'out'.
# Called via retry_delay_(). Sleep some time - see retry_delay_() - if the
# line count is still smaller than expected.
@@ -26,34 +33,41 @@ wait4lines_ ()
{
local delay=$1
local elc=$2 # Expected line count.
- [ "$( wc -l < out )" -ge "$elc" ] || { sleep $delay; return 1; }
+ [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
}
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
# === Test:
# Retry without --follow results in a warning.
touch file
tail --retry file > out 2>&1 || fail=1
-[ $( wc -l < out ) = 1 ] || fail=1
-grep -F 'tail: warning: --retry ignored' out || fail=1
+[ "$(countlines_)" = 1 ] || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
# === Test:
# The same with a missing file: expect error message and exit 1.
tail --retry missing > out 2>&1 && fail=1
-[ $( wc -l < out ) = 2 ] || fail=1
-grep -F 'tail: warning: --retry ignored' out || fail=1
+[ "$(countlines_)" = 2 ] || { cat out; fail=1; }
+grep -F 'tail: warning: --retry ignored' out || { cat out; fail=1; }
# === 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 -s.1 --follow=name --retry missing >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1 # Wait for "cannot open" error.
-echo "X" > missing || fail=1
-retry_delay_ wait4lines_ .1 6 3 || fail=1 # Wait for the expected output.
-kill $pid
-wait $pid
+timeout 10 tail $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_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
+cleanup_
# Expect 3 lines in the output file.
-[ $( wc -l < out ) = 3 ] || { fail=1; cat out; }
+[ "$(countlines_)" = 3 ] || { fail=1; cat out; }
grep -F 'cannot open' out || { fail=1; cat out; }
grep -F 'has appeared' out || { fail=1; cat out; }
grep '^X$' out || { fail=1; cat out; }
@@ -62,14 +76,15 @@ 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 -s.1 --follow=descriptor --retry missing >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 2 || fail=1 # Wait for "cannot open" error.
-echo "X" > missing || fail=1
-retry_delay_ wait4lines_ .1 6 4 || fail=1 # Wait for the expected output.
-kill $pid
-wait $pid
+timeout 10 tail $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_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+cleanup_
# Expect 4 lines in the output file.
-[ $( wc -l < out ) = 4 ] || { fail=1; cat out; }
+[ "$(countlines_)" = 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; }
@@ -80,13 +95,15 @@ 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 -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.
+timeout 10 tail $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
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
wait $pid
rc=$?
-[ $( wc -l < out ) = 4 ] || { fail=1; cat out; }
+[ "$(countlines_)" = 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; }
@@ -100,14 +117,14 @@ rm -fd missing out || framework_failure_
# 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
-[ $( wc -l < out ) = 2 ] || { fail=1; cat out; }
+[ "$(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
-[ $( wc -l < out ) = 2 ] || { fail=1; cat out; }
+[ "$(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; }
diff --git a/tests/tail-2/start-middle.sh b/tests/tail-2/start-middle.sh
index dbf9bae8..9c709aee 100755
--- a/tests/tail-2/start-middle.sh
+++ b/tests/tail-2/start-middle.sh
@@ -2,7 +2,7 @@
# Verify that tail works even when it's reading from a file
# that is not at its beginning. Based on a report from John Roll.
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2015 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
diff --git a/tests/tail-2/symlink.sh b/tests/tail-2/symlink.sh
index b21f9e15..b5dcbbd6 100755
--- a/tests/tail-2/symlink.sh
+++ b/tests/tail-2/symlink.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Ensure tail tracks symlinks properly.
-# Copyright (C) 2013-2014 Free Software Foundation, Inc.
+# Copyright (C) 2013-2015 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
@@ -19,6 +19,13 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
+# Function to count number of lines from tail
+# while ignoring transient errors due to resource limits
+countlines_ ()
+{
+ grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
+}
+
# Function to check the expected line count in 'out'.
# Called via retry_delay_(). Sleep some time - see retry_delay_() - if the
# line count is still smaller than expected.
@@ -26,43 +33,52 @@ wait4lines_ ()
{
local delay=$1
local elc=$2 # Expected line count.
- [ "$( wc -l < out )" -ge "$elc" ] || { sleep $delay; return 1; }
+ [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
}
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
# Ensure changing targets of cli specified symlinks are handled.
# Prior to v8.22, inotify would fail to recognize changes in the targets.
# Clear 'out' so that we can check its contents without races.
>out || framework_failure_
ln -nsf target symlink || framework_failure_
-timeout 10 tail -s.1 -F symlink >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1 # Wait for "cannot open..."
-echo "X" > target || fail=1
-retry_delay_ wait4lines_ .1 6 3 || fail=1 # Wait for the expected output.
-kill $pid
-wait $pid
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for "cannot open..."
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
+echo "X" > target || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 3 || { cat out; fail=1; }
+cleanup_
# Expect 3 lines in the output file.
-[ $( wc -l < out ) = 3 ] || { fail=1; cat out; }
+[ "$(countlines_)" = 3 ] || { fail=1; cat out; }
grep -F 'cannot open' out || { fail=1; cat out; }
grep -F 'has appeared' out || { fail=1; cat out; }
grep '^X$' out || { fail=1; cat out; }
rm -f target out || framework_failure_
# Ensure we correctly handle the source symlink itself changing.
-# I.E. that we don't operate solely on the targets.
+# I.e., that we don't operate solely on the targets.
# Clear 'out' so that we can check its contents without races.
>out || framework_failure_
echo "X1" > target1 || framework_failure_
ln -nsf target1 symlink || framework_failure_
-timeout 10 tail -s.1 -F symlink >out 2>&1 & pid=$!
-retry_delay_ wait4lines_ .1 6 1 || fail=1 # Wait for the expected output.
+timeout 10 tail $fastpoll -F symlink >out 2>&1 & pid=$!
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 1 || { cat out; fail=1; }
ln -nsf target2 symlink || framework_failure_
-retry_delay_ wait4lines_ .1 6 2 || fail=1 # Wait for "become inaccess..."
-echo "X2" > target2 || fail=1
-retry_delay_ wait4lines_ .1 6 4 || fail=1 # Wait for the expected output.
-kill $pid
-wait $pid
+# Wait for "become inaccess..."
+retry_delay_ wait4lines_ .1 6 2 || { cat out; fail=1; }
+echo "X2" > target2 || framework_failure_
+# Wait for the expected output.
+retry_delay_ wait4lines_ .1 6 4 || { cat out; fail=1; }
+cleanup_
# Expect 4 lines in the output file.
-[ $( wc -l < out ) = 4 ] || { fail=1; cat out; }
+[ "$(countlines_)" = 4 ] || { fail=1; cat out; }
grep -F 'become inacce' out || { fail=1; cat out; }
grep -F 'has appeared' out || { fail=1; cat out; }
grep '^X1$' out || { fail=1; cat out; }
@@ -70,7 +86,7 @@ grep '^X2$' out || { fail=1; cat out; }
rm -f target1 target2 out || framework_failure_
# Note other symlink edge cases are currently just diagnosed
-# rather than being handled. I.E. if you specify a missing item,
+# rather than being handled. I.e., if you specify a missing item,
# or existing file that later change to a symlink, if inotify
# is in use, you'll get a diagnostic saying that link will
# no longer be tailed.
diff --git a/tests/tail-2/infloop-1.sh b/tests/tail-2/tail-c.sh
index 37d081f3..04ff782b 100755
--- a/tests/tail-2/infloop-1.sh
+++ b/tests/tail-2/tail-c.sh
@@ -1,7 +1,7 @@
#!/bin/sh
-# This test would fail with tail from pre-1.22i textutils.
+# exercise tail -c
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright 2014-2015 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
@@ -19,28 +19,16 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
-yes > t &
-yes_pid=$!
-while :; do
- test -s t \
- && break
- sleep .1
-done
-tail -n 1 t &
-tail_pid=$!
-kill $yes_pid
-
-# This test is racy, and can fail under unusual circumstances.
-# On a very busy system, tail will fail to notice that $yes_pid is gone.
-# Then the following kill will succeed and cause this test to fail.
-
-# Wait for up to 3 seconds for tail to detect the death of $yes_pid.
-for i in $(seq 30); do
- kill -0 $tail_pid || break
- echo sleep 0.1s
- sleep .1
-done
+# Make sure it works on funny files in /proc and /sys.
-kill $tail_pid && fail=1 || :
+for file in /proc/version /sys/kernel/profiling; do
+ if test -r $file; then
+ cp -f $file copy &&
+ tail -c -1 copy > exp1 || framework_failure_
+
+ tail -c -1 $file > out1 || fail=1
+ compare exp1 out1 || fail=1
+ fi
+done
Exit $fail
diff --git a/tests/tail-2/tail-n0f.sh b/tests/tail-2/tail-n0f.sh
index 1d020ac9..ba9f4071 100755
--- a/tests/tail-2/tail-n0f.sh
+++ b/tests/tail-2/tail-n0f.sh
@@ -2,7 +2,7 @@
# Make sure that 'tail -n0 -f' and 'tail -c0 -f' sleep
# rather than doing what amounted to a busy-wait.
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2015 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
@@ -35,11 +35,13 @@ chmod 0 unreadable || framework_failure_
tail -c0 unreadable || fail=1
tail -n0 unreadable || fail=1
-for inotify in ---disable-inotify ''; do
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+for mode in '' '---disable-inotify'; do
for file in empty nonempty; do
for c_or_n in c n; do
- tail --sleep=4 -${c_or_n} 0 -f $inotify $file &
- pid=$!
+ tail --sleep=4 -${c_or_n} 0 -f $mode $file & pid=$!
tail_sleeping()
{
local delay="$1"; sleep $delay
@@ -52,7 +54,7 @@ for inotify in ---disable-inotify ''; do
# Wait up to 1.5s for tail to sleep
retry_delay_ tail_sleeping .1 4 ||
{ echo $0: process in unexpected state: $state >&2; fail=1; }
- kill $pid
+ cleanup_
done
done
done
diff --git a/tests/tail-2/truncate.sh b/tests/tail-2/truncate.sh
new file mode 100755
index 00000000..82720fda
--- /dev/null
+++ b/tests/tail-2/truncate.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# Ensure all logs are output upon file truncation
+
+# Copyright (C) 2015 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
+
+check_tail_output()
+{
+ local delay="$1"
+ grep "$tail_re" out > /dev/null ||
+ { sleep $delay; return 1; }
+}
+
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# Speedup the non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
+
+for follow in '-f' '-F'; do
+ for mode in '' '---disable-inotify'; do
+ rm -f out
+ seq 10 > f || framework_failure_
+
+ tail $follow $mode $fastpoll f > out 2>&1 & pid=$!
+
+ # Wait up to 12.7s for tail to start
+ tail_re='^10$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ seq 11 15 > f || framework_failure_
+
+ # Wait up to 12.7s for new data
+ tail_re='^15$' retry_delay_ check_tail_output .1 7 ||
+ { cat out; fail=1; }
+
+ cleanup_
+ done
+done
+
+Exit $fail
diff --git a/tests/tail-2/wait.sh b/tests/tail-2/wait.sh
index 3dec55c0..2e58e821 100755
--- a/tests/tail-2/wait.sh
+++ b/tests/tail-2/wait.sh
@@ -2,7 +2,7 @@
# Make sure that 'tail -f' returns immediately if a file doesn't exist
# while 'tail -F' waits for it to appear.
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2015 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
@@ -20,47 +20,60 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
+grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null \
+ && HAVE_INOTIFY=1
+
+inotify_failed_re='inotify (resources exhausted|cannot be used)'
+
touch here || framework_failure_
{ touch unreadable && chmod a-r unreadable; } || framework_failure_
+# Terminate any background tail process
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+
+# speedup non inotify case
+fastpoll='-s.1 --max-unchanged-stats=1'
-for inotify in ---disable-inotify ''; do
- timeout 10 tail -s0.1 -f $inotify not_here
+for mode in '' '---disable-inotify'; do
+ timeout 10 tail $fastpoll -f $mode not_here
test $? = 124 && fail=1
if test ! -r unreadable; then # can't test this when root
- timeout 10 tail -s0.1 -f $inotify unreadable
+ timeout 10 tail $fastpoll -f $mode unreadable
test $? = 124 && fail=1
fi
- timeout 1 tail -s0.1 -f $inotify here 2>tail.err
+ timeout .1 tail $fastpoll -f $mode here 2>tail.err
test $? = 124 || fail=1
# 'tail -F' must wait in any case.
- timeout 1 tail -s0.1 -F $inotify here 2>>tail.err
+ timeout .1 tail $fastpoll -F $mode here 2>>tail.err
test $? = 124 || fail=1
if test ! -r unreadable; then # can't test this when root
- timeout 1 tail -s0.1 -F $inotify unreadable
+ timeout .1 tail $fastpoll -F $mode unreadable
test $? = 124 || fail=1
fi
- timeout 1 tail -s0.1 -F $inotify not_here
+ timeout .1 tail $fastpoll -F $mode not_here
test $? = 124 || fail=1
- grep -Ev 'inotify (resources exhausted|cannot be used)' tail.err > x
+ grep -Ev "$inotify_failed_re" tail.err > x
mv x tail.err
compare /dev/null tail.err || fail=1
>tail.err
+done
+if test "$HAVE_INOTIFY"; then
+ # Ensure -F never follows a descriptor after rename
+ # either with tiny or significant delays between operations
tail_F()
{
local delay="$1"
touch k || framework_failure_
- tail -s.1 --max-unchanged-stats=2 -F $inotify k > tail.out &
- pid=$!
+ tail $fastpoll -F $mode k >tail.out 2>tail.err & pid=$!
sleep $delay
mv k l
sleep $delay
@@ -69,12 +82,15 @@ for inotify in ---disable-inotify ''; do
sleep $delay
echo NO >> l
sleep $delay
- kill $pid
+ cleanup_
rm -f k l
- test ! -s tail.out
+ test -s tail.out \
+ && ! grep -E "$inotify_failed_re" tail.err >/dev/null
}
- retry_delay_ tail_F .1 4 || fail=1
-done
+
+ retry_delay_ tail_F 0 1 && { cat tail.out; fail=1; }
+ retry_delay_ tail_F .2 1 && { cat tail.out; fail=1; }
+fi
Exit $fail