1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-25 07:36:29 +00:00
cde/src/cmd/ksh93/tests/signal.sh
Martijn Dekker d3cd4cf906 Fixes to compile on Solaris variants, NetBSD, and NixOS
Solaris, Illumos distributions, and NetBSD need LDFLAGS set to link
explicitly to libm, otherwise, due to as-yet unknown reasons, the
src/lib/libdll/features/dll fails to write a valid header file and
compilation fails due to unknown identifiers such as Dllscan_t.
This commit adds the flag on those systems.

NixOS is a Linux distro that uses very different paths from the
usual Unix conventions (though it's POSIX compliant), and the
regression tests still needed a lot of tweaks to be compatible.

src/cmd/INIT/package.sh, bin/package:
- On SunOS (Solaris and illumos distros) and NetBSD, add '-lm' to
  LDFLAGS before compiling.

src/cmd/INIT/mamprobe.sh, bin/mamprobe,
src/cmd/INIT/execrate.sh, bin/execrate:
- Instead of only in /bin, /usr/bin, /sbin and /usr/sbin, search
  utilities in the path given by the OS 'getconf PATH', and use the
  user's original $PATH as a fallback.

src/cmd/ksh93/tests/*.sh:
- Miscellaneous portability fixes, mainly elimination of unportable
  hardcoded paths to commands.
- basic.sh: Remove test for 'time' keyword millisecond precision.
  It was racy and could fail depending on system and system load.
2020-08-03 09:24:16 +01:00

470 lines
13 KiB
Bash
Executable file

########################################################################
# #
# This software is part of the ast package #
# Copyright (c) 1982-2012 AT&T Intellectual Property #
# and is licensed under the #
# Eclipse Public License, Version 1.0 #
# by AT&T Intellectual Property #
# #
# A copy of the License is available at #
# http://www.eclipse.org/org/documents/epl-v10.html #
# (with md5 checksum b35adb5213ca9657e911e9befb180842) #
# #
# Information and Software Systems Research #
# AT&T Research #
# Florham Park NJ #
# #
# David Korn <dgk@research.att.com> #
# #
########################################################################
function err_exit
{
print -u2 -n "\t"
print -u2 -r ${Command}[$1]: "${@:2}"
(( Errors++ ))
}
alias err_exit='err_exit $LINENO'
Command=${0##*/}
integer Errors=0
[[ -d $tmp && -w $tmp ]] || { err\_exit "$LINENO" '$tmp not set; run this from shtests. Aborting.'; exit 1; }
CDPATH= cd -P -- "$tmp" || exit
unset n s t
typeset -A SIG
for s in $(kill -l)
do if ! n=$(kill -l $s 2>/dev/null)
then err_exit "'kill -l $s' failed"
elif ! t=$(kill -l $n 2>/dev/null)
then err_exit "'kill -l $n' failed"
elif [[ $s == ?(SIG)$t ]]
then SIG[${s#SIG}]=1
elif ! m=$(kill -l $t 2>/dev/null)
then err_exit "'kill -l $t' failed"
elif [[ $m != $n ]]
then err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n"
fi
done
(
: disabling xtrace for this test
set +x --pipefail
{
$SHELL 2> out2 <<- \EOF
g=false
trap 'print -u2 PIPED; $g && exit 0;g=true' PIPE
while :
do print hello
done
EOF
} | head > /dev/null
(( $? == 0)) || err_exit "SIGPIPE with wrong error code $?"
# The below is kind of bogus as the err_exit from a bg job is never counted. But see extra check below.
[[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct'
) &
cop=$!
{ sleep .4; kill $cop; } 2>/dev/null &
spy=$!
if wait $cop 2>/dev/null
then kill $spy 2>/dev/null
else err_exit "pipe with --pipefail PIPE trap hangs or produced an error"
fi
wait
rm -f out2
[[ $( trap 'print -n got_child' SIGCHLD
sleep .2 &
for ((i=0; i < 4; i++))
do sleep .075
print -n $i
done) == 01got_child23 ]] || err_exit 'SIGCHLD not working'
# begin standalone SIGINT test generation
cat > tst <<'!'
# shell trap tests
#
# tst control script that calls tst-1, must be run by ksh
# tst-1 calls tst-2
# tst-2 calls tst-3
# tst-3 defaults or handles and discards/propagates SIGINT
#
# initial -v option lists script entry and SIGINT delivery
#
# three test options
#
# d call next script directly, otherwise via $SHELL -c
# t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x
# x trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit, otherwise SIGINT default
# z trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit 0, otherwise SIGINT default
#
# Usage: tst [-v] [-options] shell-to-test ...
# "trap + sig" is an unadvertized extension for this test
# if run from nmake SIGINT is set to SIG_IGN
# this call sets it back to SIG_DFL
# semantics w.r.t. function scope must be worked out before
# making it public
trap + INT
set -o monitor
function gen
{
typeset o t x d
for x in - x z
do case $x in
[$1]) for t in - t
do case $t in
[$1]) for d in - d
do case $d in
[$1]) o="$o $x$t$d"
esac
done
esac
done
esac
done
echo '' $o
}
case $1 in
-v) v=v; shift ;;
-*v*) v=v ;;
*) v= ;;
esac
case $1 in
*' '*) o=$1; shift ;;
-*) o=$(gen $1); shift ;;
*) o=$(gen -txd) ;;
esac
case $# in
0) set ksh bash ksh88 pdksh ash zsh ;;
esac
for f in $o
do case $# in
1) ;;
*) echo ;;
esac
for sh
do if $sh -c 'exit 0' > /dev/null 2>&1
then case $# in
1) printf '%3s ' "$f" ;;
*) printf '%16s %3s ' "$sh" "$f" ;;
esac
$sh tst-1 $v$f $sh > tst.out &
wait
echo $(cat tst.out)
fi
done
done
case $# in
1) ;;
*) echo ;;
esac
!
cat > tst-1 <<'!'
exec 2>/dev/null
case $1 in
*v*) echo 1-main ;;
esac
{
sleep .2
case $1 in
*v*) echo "SIGINT" ;;
esac
kill -s INT 0
} &
case $1 in
*t*) trap '
echo 1-intr
trap - INT
# omitting the self kill exposes shells that deliver
# the SIGINT trap but exit 0 for -xt
# kill -s INT $$
' INT
;;
esac
case $1 in
*d*) tst-2 $1 $2; status=$? ;;
*) $2 -c "tst-2 $1 $2"; status=$? ;;
esac
printf '1-%04d\n' $status
sleep .2
!
cat > tst-2 <<'!'
case $1 in
*z*) trap '
echo 2-intr
exit 0
' INT
;;
*x*) trap '
echo 2-intr
exit
' INT
;;
*t*) trap '
echo 2-intr
trap - INT
kill -s INT $$
' INT
;;
esac
case $1 in
*v*) echo 2-main ;;
esac
case $1 in
*d*) tst-3 $1 $2; status=$? ;;
*) $2 -c "tst-3 $1 $2"; status=$? ;;
esac
printf '2-%04d\n' $status
!
cat > tst-3 <<'!'
case $1 in
*[xz]*) trap '
sleep .2
echo 3-intr
exit 0
' INT
;;
*) trap '
sleep .2
echo 3-intr
trap - INT
kill -s INT $$
' INT
;;
esac
case $1 in
*v*) echo 3-main ;;
esac
sleep .5
printf '3-%04d\n' $?
!
chmod +x tst tst-?
# end standalone test generation
export PATH=$PATH:
typeset -A expected
expected[---]="3-intr"
expected[--d]="3-intr"
expected[-t-]="3-intr 2-intr 1-intr 1-0258"
expected[-td]="3-intr 2-intr 1-intr 1-0258"
expected[x--]="3-intr 2-intr 1-0000"
expected[x-d]="3-intr 2-intr 1-0000"
expected[xt-]="3-intr 2-intr 1-intr 1-0000"
expected[xtd]="3-intr 2-intr 1-intr 1-0000"
expected[z--]="3-intr 2-intr 1-0000"
expected[z-d]="3-intr 2-intr 1-0000"
expected[zt-]="3-intr 2-intr 1-intr 1-0000"
expected[ztd]="3-intr 2-intr 1-intr 1-0000"
tst $SHELL > tst.got
while read ops out
do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- expected '${expected[$ops]}', got '$out'"
done < tst.got
if [[ ${SIG[USR1]} ]]
then float s=$SECONDS
[[ $(LC_ALL=C $SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "" USR1 ; exec kill -USR1 $$ & sleep .5); print done') == SIGUSR1 ]] || err_exit 'subshell ignoring signal does not send signal to parent'
(( (SECONDS-s) < .4 )) && err_exit 'parent does not wait for child to complete before handling signal'
((s = SECONDS))
[[ $(LC_ALL=C $SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "exit" USR1 ; exec kill -USR1 $$ & sleep .5); print done') == SIGUSR1 ]] || err_exit 'subshell catching signal does not send signal to parent'
(( SECONDS-s < .4 )) && err_exit 'parent completes early'
fi
yes() for ((;;)); do print y; done
for exp in TERM VTALRM PIPE
do if [[ ${SIG[$exp]} ]]
then {
bindate=$(whence -p date) "$SHELL" <<- EOF
foo() { return 0; }
trap foo EXIT
{ sleep .2; kill -$exp \$\$; sleep .3; kill -0 \$\$ && kill -KILL \$\$; } &
yes |
while read yes
do ("\$bindate"; sleep .01)
done > /dev/null
EOF
} 2>> /dev/null
got=$(kill -l $?)
[[ $exp == $got ]] || err_exit "kill -$exp \$\$ failed, required termination by signal '$got'"
fi
done
SECONDS=0
$SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; (sleep .5); print finished' > $tmp/sig
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
x=$(<$tmp/sig)
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
SECONDS=0
$SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; sleep .5; print finished' > $tmp/sig
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
x=$(<$tmp/sig)
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
SECONDS=0
{ $SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; (sleep .5); print finished' > $tmp/sig ;} 2> /dev/null
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
x=$(<$tmp/sig)
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
SECONDS=0
{ $SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; sleep .5; print finished' > $tmp/sig ;} 2> /dev/null
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
x=$(<$tmp/sig)
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
SECONDS=0
x=$($SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; (sleep .5); print finished')
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
SECONDS=0
x=$($SHELL 2> /dev/null -c 'sleep .2 && kill $$ & trap "print done; exit 3" EXIT; sleep .5; print finished')
e=$?
[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e"
[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'"
(( SECONDS > .35 )) && err_exit "took $SECONDS seconds, expected around .2"
trap '' SIGBUS
[[ $($SHELL -c 'trap date SIGBUS; trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap'
trap -- - SIGBUS
{
x=$(
$SHELL <<- \++EOF
timeout()
{
trap 'trap - TERM; return' TERM
( sleep $1; kill -TERM $$ ) >/dev/null 2>&1 &
sleep .3
}
timeout .1
print ok
++EOF
)
} 2> /dev/null
[[ $x == ok ]] || err_exit 'return without arguments in trap not preserving exit status'
x=$(
$SHELL <<- \++EOF
set -o pipefail
foobar()
{
for ((i=0; i < 10000; i++))
do print abcdefghijklmnopqrstuvwxyz
done | head > /dev/null
}
foobar
print ok
++EOF
)
[[ $x == ok ]] || err_exit 'SIGPIPE exit status causes PIPE signal to be propogaged'
x=$(
$SHELL <<- \EOF
trap "print GNAW" URG
print 1
( sleep .1 ; kill -URG $$ ; sleep .1 ; print S1 ; )
print 2
EOF
)
[[ $x == $'1\nS1\nGNAW\n2' ]] || err_exit 'signal ignored in subshell not propagated to parent'
if [[ ${SIG[RTMIN]} ]]
then {
$SHELL <<- \EOF
trap : RTMIN
for ((i=0 ; i < 3 ; i++))
do sleep .1
kill -RTMIN $$ 2> /dev/null
done &
wait
EOF
} 2> /dev/null
[[ $? == 0 ]] && err_exit 'wait interrupted by caught signal should have non-zero exit status'
{
$SHELL <<- \EOF
for ((i=0 ; i < 3 ; i++))
do sleep .1
kill -RTMIN $$ 2> /dev/null
done &
wait
EOF
} 2> /dev/null
[[ $(kill -l $?) == RTMIN ]] || err_exit 'wait interrupted by signal not caught should exit with the value of that signal+256'
fi
function b
{
sleep .3
endb=1
}
function a
{
trap 'print int' TERM
b
enda=1
}
{ sleep .1;kill -s TERM $$;}&
unset enda endb
a
[[ $endb ]] && err_exit 'TERM signal did not kill function b'
[[ $enda == 1 ]] || err_exit 'TERM signal killed function a'
# ======
# Exit status checks
# Verify that 'exit x' for x > 256 does not make the shell send a signal to itself
"$SHELL" -c 'exit $((256+9))'
let "$? == 256+9" && err_exit 'exit with status > 256 makes shell kill itself'
# Verify that the shell does not kill itself after detecting that a child process is killed by a signal,
# and that a signal still causes the exit status to be set to a value > 128
cat >"$tmp/sigtest.sh" <<\EOF
echo begin
"$1" -c 'kill -9 "$$"'
EOF
expect=$'^begin\n/.*/sigtest.sh: line 2: [1-9][0-9]*: Killed\n[1-9][0-9]{1,2}$'
actual=$(LANG=C "$SHELL" -c '"$1" "$2" "$1"; echo "$?"' x "$SHELL" "$tmp/sigtest.sh" 2>&1)
if ! [[ $actual =~ $expect ]]
then [[ $actual == *Killed*Killed* ]] && msg='ksh killed itself' || msg='unexpected output'
err_exit "$msg after child process signal (expected match to $(printf %q "$expect"); got $(printf %q "$actual"))"
fi
let "${actual##*$'\n'} > 128" || err_exit "child process signal did not cause exit status > 128"
# ======
# Killing a non-existent job shouldn't cause a segfault. Note that `2> /dev/null` has no effect when
# there is a segfault.
$SHELL -c 'kill %% 2> /dev/null'; [[ $? == 1 ]] || err_exit $'`kill` doesn\'t handle a non-existent job correctly when passed \'%%\''
$SHELL -c 'kill %+ 2> /dev/null'; [[ $? == 1 ]] || err_exit $'`kill` doesn\'t handle a non-existent job correctly when passed \'%+\''
$SHELL -c 'kill %- 2> /dev/null'; [[ $? == 1 ]] || err_exit $'`kill` doesn\'t handle a non-existent job correctly when passed \'%-\''
# ======
# SIGINFO should be supported by the kill builtin on platforms that have it.
if "$(whence -p kill)" -INFO $$ 2> /dev/null
then
kill -INFO $$ || err_exit '`kill` cannot send SIGINFO to processes when passed `-INFO`'
fi
# ======
exit $((Errors<125?Errors:125))