File: env-signal-handler.sh

package info (click to toggle)
coreutils 9.10-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 70,560 kB
  • sloc: ansic: 253,546; sh: 30,931; perl: 8,141; yacc: 1,846; makefile: 198; python: 47; sed: 16
file content (169 lines) | stat: -rwxr-xr-x 6,278 bytes parent folder | download
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/bin/sh
# Test env --default-signal=PIPE feature.

# Copyright (C) 2019-2026 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
# This test also relies on bash's 'kill' builtin which allows the signal name
# "RTMIN" and "RTMAX" if those real-time signals are supported.
require_bash_as_SHELL_

# Paraphrasing https://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

env_ignore_delay_()
{
  local delay="$1"

  # The first 'env' is just to ensure timeout is not a shell built-in.
  env timeout --verbose --kill-after=.1 --signal=$timeout_sig $delay \
    env $env_opt sleep 10 > /dev/null 2>outt
  # 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' outt > out || framework_failure_
  compare exp out
}

# Baseline test - ignore signal handler
# -------------------------------------
# Terminate 'sleep' with SIGINT
# (SIGINT's default action is to terminate a program).
cat <<\EOF >exp || framework_failure_
timeout: sending signal INT to command 'env'
EOF
timeout_sig=INT env_opt='' \
  retry_delay_ env_ignore_delay_ .1 6 || fail=1

# env test - ignore signal handler
# --------------------------------
# Use env to ignore SIGINT - "sleep" should continue running
# after timeout sends SIGINT, and be killed using SIGKILL.
cat <<\EOF >exp || framework_failure_
timeout: sending signal INT to command 'env'
timeout: sending signal KILL to command 'env'
EOF
timeout_sig=INT env_opt='--ignore-signal=INT' \
  retry_delay_ env_ignore_delay_ .1 6 || fail=1
timeout_sig=INT env_opt='--ignore-signal' \
  retry_delay_ env_ignore_delay_ .1 6 || fail=1

# env test - ignore signal handler for PIPE
# SIGPIPE is often incorrectly interfered with, as per:
# http://www.pixelbeat.org/programming/sigpipe_handling.html
cat <<\EOF >exp || framework_failure_
timeout: sending signal PIPE to command 'env'
timeout: sending signal KILL to command 'env'
EOF
timeout_sig=PIPE env_opt='--ignore-signal=PIPE' \
  retry_delay_ env_ignore_delay_ .1 6 || fail=1

if kill -l RTMIN RTMAX; then
  for sig in RTMIN RTMAX; do
    # Baseline test - ignore signal handler
    # -------------------------------------
    # Terminate 'sleep' with $sig
    # All real-time signals terminate the program by default.
    cat <<EOF >exp || framework_failure_
timeout: sending signal $sig to command 'env'
EOF
    timeout_sig=$sig env_opt='' \
      retry_delay_ env_ignore_delay_ .1 6 || fail=1

    # env test - ignore signal handler
    # --------------------------------
    # Use env to ignore $sig - "sleep" should continue running
    # after timeout sends $sig, and be killed using SIGKILL.
    cat <<EOF >exp || framework_failure_
timeout: sending signal $sig to command 'env'
timeout: sending signal KILL to command 'env'
EOF
    timeout_sig=$sig env_opt="--ignore-signal=$sig" \
      retry_delay_ env_ignore_delay_ .1 6 || fail=1
    timeout_sig=$sig env_opt='--ignore-signal' \
      retry_delay_ env_ignore_delay_ .1 6 || fail=1
  done
fi

# env test --list-signal-handling
for sig in INT PIPE; do
  env --default-signal --ignore-signal=$sig --list-signal-handling true \
    2> err8t || fail=1
  sed 's/ *(.*)//' err8t > err8 || framework_failure_
  env printf '%s: IGNORE\n' "$sig" > exp-err8 || framework_failure_
  compare exp-err8 err8 || fail=1
done

Exit $fail