summaryrefslogtreecommitdiffstats
path: root/tests/misc/env-signal-handler.sh
blob: c38177dae5057feead71694036144ef62c79a006 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/bin/sh
# Test env --default-signal=PIPE feature.

# Copyright (C) 2019-2020 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 <https://www.gnu.org/licenses/>.

. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ env seq test timeout printf
trap_sigpipe_or_skip_

# /bin/sh has an intermittent failure in ignoring SIGPIPE on OpenIndiana 11
# so we require bash as discussed at:
# https://lists.gnu.org/archive/html/coreutils/2020-03/msg00004.html
require_bash_as_SHELL_

# Paraphrasing http://bugs.gnu.org/34488#8:
# POSIX requires that sh started with an inherited ignored SIGPIPE must
# silently ignore all attempts from within the shell to restore SIGPIPE
# handling to child processes of the shell:
#
#    $ (trap '' PIPE; bash -c 'trap - PIPE; seq inf | head -n1')
#    1
#    seq: write error: Broken pipe
#
# With 'env --default-signal=PIPE', the signal handler can be reset to its
# default.

# Baseline Test - default signal handler
# --------------------------------------
# Ensure this results in a "broken pipe" error (the first 'trap'
# sets SIGPIPE to ignore, and the second 'trap' becomes a no-op instead
# of resetting SIGPIPE to its default). Upon a SIGPIPE 'seq' will not be
# terminated, instead its write(2) call will return an error.
(trap '' PIPE; $SHELL -c 'trap - PIPE; seq 999999 2>err1t | head -n1 > out1')

# The exact broken pipe message depends on the operating system, just ensure
# there was a 'write error' message in stderr:
sed 's/^\(seq: write error:\) .*/\1/' err1t > err1 || framework_failure_

printf "1\n" > exp-out || framework_failure_
printf "seq: write error:\n" > exp-err1 || framework_failure_

compare exp-out out1 || framework_failure_
compare exp-err1 err1 || framework_failure_


# env test - default signal handler
# ---------------------------------
# With env resetting the signal handler to its defaults, there should be no
# error message (because the default SIGPIPE action is to terminate the
# 'seq' program):
(trap '' PIPE;
 env --default-signal=PIPE \
    $SHELL -c 'trap - PIPE; seq 999999 2>err2 | head -n1 > out2')

compare exp-out out2 || fail=1
compare /dev/null err2 || fail=1

# env test - default signal handler (3)
# -------------------------------------
# Repeat the previous test, using --default-signal with no signal names,
# i.e., all signals.
(trap '' PIPE;
 env --default-signal \
    $SHELL -c 'trap - PIPE; seq 999999 2>err4 | head -n1 > out4')

compare exp-out out4 || fail=1
compare /dev/null err4 || fail=1

# env test - block signal handler
env --block-signal true || fail=1

# Baseline test - ignore signal handler
# -------------------------------------
# Kill 'sleep' after 1 second with SIGINT - it should terminate (as SIGINT's
# default action is to terminate a program).
# (The first 'env' is just to ensure timeout is not the shell's built-in.)
env timeout --verbose --kill-after=.1 --signal=INT .1 \
    sleep 10 > /dev/null 2>err5

printf "timeout: sending signal INT to command 'sleep'\n" > exp-err5 \
    || framework_failure_

compare exp-err5 err5 || fail=1


# env test - ignore signal handler
# --------------------------------
# Use env to silence (ignore) SIGINT - "seq" should continue running
# after timeout sends SIGINT, and be killed after 1 second using SIGKILL.

cat>exp-err6 <<EOF
timeout: sending signal INT to command 'env'
timeout: sending signal KILL to command 'env'
EOF

env timeout --verbose --kill-after=.1 --signal=INT .1 \
    env --ignore-signal=INT \
    sleep 10 > /dev/null 2>err6t

# check only the first two lines from stderr, which are printed by timeout.
# (operating systems might add more messages, like "killed").
sed -n '1,2p' err6t > err6 || framework_failure_

compare exp-err6 err6 || fail=1


# env test - ignore signal handler (2)
# ------------------------------------
# Repeat the previous test with "--ignore-signals" and no signal names,
# i.e., all signals.

env timeout --verbose --kill-after=.1 --signal=INT .1 \
    env --ignore-signal \
    sleep 10 > /dev/null 2>err7t

# check only the first two lines from stderr, which are printed by timeout.
# (operating systems might add more messages, like "killed").
sed -n '1,2p' err7t > err7 || framework_failure_

compare exp-err6 err7 || fail=1


# env test --list-signal-handling
env --default-signal --ignore-signal=INT --list-signal-handling true \
  2> err8t || fail=1
sed 's/(.*)/()/' err8t > err8 || framework_failure_
env printf 'INT        (): IGNORE\n' > exp-err8
compare exp-err8 err8 || fail=1


Exit $fail