1#!/bin/sh
2# inotify-based tail would output redundant headers for
3# overlapping inotify events while it was suspended
4
5# Copyright (C) 2017-2023 Free Software Foundation, Inc.
6
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
20. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
21print_ver_ tail sleep
22
23# Function to count number of lines from tail
24# while ignoring transient errors due to resource limits
25countlines_ ()
26{
27  grep -Ev 'inotify (resources exhausted|cannot be used)' out | wc -l
28}
29
30# Function to check the expected line count in 'out'.
31# Called via retry_delay_().  Sleep some time - see retry_delay_() - if the
32# line count is still smaller than expected.
33wait4lines_ ()
34{
35  local delay=$1
36  local elc=$2   # Expected line count.
37  [ "$(countlines_)" -ge "$elc" ] || { sleep $delay; return 1; }
38}
39
40# Speedup the non inotify case
41fastpoll='---dis -s.1 --max-unchanged-stats=1'
42
43# Terminate any background tail process
44cleanup_() {
45  kill $pid 2>/dev/null && wait $pid;
46  kill $sleep 2>/dev/null && wait $sleep
47}
48
49echo start > file1 || framework_failure_
50echo start > file2 || framework_failure_
51
52# Use this as a way to gracefully terminate tail
53env sleep 20 & sleep=$!
54
55tail $fastpoll --pid=$sleep -f file1 file2 > out & pid=$!
56
57kill -0 $pid || fail=1
58
59# Wait for 5 initial lines
60retry_delay_ wait4lines_ .1 6 5 || fail=1
61
62# Suspend tail so single read() caters for multiple inotify events
63kill -STOP $pid || fail=1
64
65# Interleave writes to files to generate overlapping inotify events
66echo line >> file1 || framework_failure_
67echo line >> file2 || framework_failure_
68echo line >> file1 || framework_failure_
69echo line >> file2 || framework_failure_
70
71# Resume tail processing
72kill -CONT $pid || fail=1
73
74# Wait for 8 more lines
75retry_delay_ wait4lines_ .1 6 13 || fail=1
76
77kill $sleep && wait || framework_failure_
78
79test "$(countlines_)" = 13 || fail=1
80
81Exit $fail
82