1#!/bin/sh
2# Makes sure, inotify will switch to polling mode if directory
3# of the watched file was removed and recreated.
4# (...instead of getting stuck forever)
5
6# Copyright (C) 2017-2023 Free Software Foundation, Inc.
7
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
21. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
22print_ver_ tail
23
24grep '^#define HAVE_INOTIFY 1' "$CONFIG_HEADER" >/dev/null && is_local_dir_ . \
25  || skip_ 'inotify is not supported'
26
27# Terminate any background tail process
28cleanup_() { kill $pid 2>/dev/null && wait $pid; }
29
30cleanup_fail_ ()
31{
32  warn_ $1
33  cleanup_
34  fail=1
35}
36
37# $check_re - string to be found
38# $check_f - file to be searched
39check_tail_output_ ()
40{
41  local delay="$1"
42  grep $check_re $check_f > /dev/null ||
43    { sleep $delay ; return 1; }
44}
45
46grep_timeout_ ()
47{
48  check_re="$1"
49  check_f="$2"
50  retry_delay_ check_tail_output_ .1 5
51}
52
53# Prepare the file to be watched
54mkdir dir && echo 'inotify' > dir/file || framework_failure_
55
56#tail must print content of the file to stdout, verify
57timeout 60 tail --pid=$$ -F dir/file >out 2>&1 & pid=$!
58grep_timeout_ 'inotify' 'out' ||
59{ cleanup_fail_ 'file to be tailed does not exist'; }
60
61inotify_failed_re='inotify (resources exhausted|cannot be used)'
62grep -E "$inotify_failed_re" out &&
63  skip_ "inotify can't be used"
64
65# Remove the directory, should get the message about the deletion
66rm -r dir || framework_failure_
67grep_timeout_ 'polling' 'out' ||
68{ cleanup_fail_ 'tail did not switch to polling mode'; }
69
70# Recreate the dir, must get a message about recreation
71mkdir dir && touch dir/file || framework_failure_
72grep_timeout_ 'appeared' 'out' ||
73{ cleanup_fail_ 'previously removed file did not appear'; }
74
75cleanup_
76
77# Expected result for the whole process
78cat <<\EOF > exp || framework_failure_
79inotify
80tail: 'dir/file' has become inaccessible: No such file or directory
81tail: directory containing watched file was removed
82tail: inotify cannot be used, reverting to polling
83tail: 'dir/file' has appeared;  following new file
84EOF
85
86compare exp out || fail=1
87
88Exit $fail
89