1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2010 AT&T Intellectual Property # 5# and is licensed under the # 6# Common Public License, Version 1.0 # 7# by AT&T Intellectual Property # 8# # 9# A copy of the License is available at # 10# http://www.opensource.org/licenses/cpl1.0.txt # 11# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 12# # 13# Information and Software Systems Research # 14# AT&T Research # 15# Florham Park NJ # 16# # 17# David Korn <dgk@research.att.com> # 18# # 19######################################################################## 20function err_exit 21{ 22 print -u2 -n "\t" 23 print -u2 -r ${Command}[$1]: "${@:2}" 24 (( Errors++ )) 25} 26alias err_exit='err_exit $LINENO' 27 28Command=${0##*/} 29integer Errors=0 30 31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } 32trap "cd /; rm -rf $tmp" EXIT 33 34cd $tmp || err_exit "cd $tmp failed" 35 36( 37 set --pipefail 38 { 39 $SHELL 2> out2 <<- \EOF 40 g=false 41 trap 'print -u2 PIPED; $g && exit 0;g=true' PIPE 42 while : 43 do print hello 44 done 45 EOF 46 } | head > /dev/null 47 (( $? == 0)) || err_exit "SIGPIPE with wrong error code $?" 48 [[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct' 49) & 50cop=$! 51{ sleep 4; kill $cop; } 2>/dev/null & 52spy=$! 53if wait $cop 2>/dev/null 54then kill $spy 2>/dev/null 55else err_exit "pipe with --pipefail PIPE trap hangs" 56fi 57wait 58rm -f out2 59 60[[ $( trap 'print -n got_child' SIGCHLD 61 sleep 2 & 62 for ((i=0; i < 4; i++)) 63 do sleep .75 64 print -n $i 65 done) == 01got_child23 ]] || err_exit 'SIGCHLD not working' 66 67# begin standalone SIGINT test generation 68 69cat > tst <<'!' 70# shell trap tests 71# 72# tst control script that calls tst-1, must be run by ksh 73# tst-1 calls tst-2 74# tst-2 calls tst-3 75# tst-3 defaults or handles and discards/propagates SIGINT 76# 77# initial -v option lists script entry and SIGINT delivery 78# 79# three test options 80# 81# d call next script directly, otherwise via $SHELL -c 82# t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x 83# x trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit, otherwise SIGINT default 84# z trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit 0, otherwise SIGINT default 85# 86# Usage: tst [-v] [-options] shell-to-test ... 87 88# "trap + sig" is an unadvertized extension for this test 89# if run from nmake SIGINT is set to SIG_IGN 90# this call sets it back to SIG_DFL 91# semantics w.r.t. function scope must be worked out before 92# making it public 93trap + INT 94 95set -o monitor 96 97function gen 98{ 99 typeset o t x d 100 for x in - x z 101 do case $x in 102 [$1]) for t in - t 103 do case $t in 104 [$1]) for d in - d 105 do case $d in 106 [$1]) o="$o $x$t$d" 107 esac 108 done 109 esac 110 done 111 esac 112 done 113 echo '' $o 114} 115 116case $1 in 117-v) v=v; shift ;; 118-*v*) v=v ;; 119*) v= ;; 120esac 121case $1 in 122*' '*) o=$1; shift ;; 123-*) o=$(gen $1); shift ;; 124*) o=$(gen -txd) ;; 125esac 126case $# in 1270) set ksh bash ksh88 pdksh ash zsh ;; 128esac 129for f in $o 130do case $# in 131 1) ;; 132 *) echo ;; 133 esac 134 for sh 135 do if $sh -c 'exit 0' > /dev/null 2>&1 136 then case $# in 137 1) printf '%3s ' "$f" ;; 138 *) printf '%16s %3s ' "$sh" "$f" ;; 139 esac 140 $sh tst-1 $v$f $sh > tst.out & 141 wait 142 echo $(cat tst.out) 143 fi 144 done 145done 146case $# in 1471) ;; 148*) echo ;; 149esac 150! 151cat > tst-1 <<'!' 152exec 2>/dev/null 153case $1 in 154*v*) echo 1-main ;; 155esac 156{ 157 sleep 2 158 case $1 in 159 *v*) echo "SIGINT" ;; 160 esac 161 kill -s INT 0 162} & 163case $1 in 164*t*) trap ' 165 echo 1-intr 166 trap - INT 167 # omitting the self kill exposes shells that deliver 168 # the SIGINT trap but exit 0 for -xt 169 # kill -s INT $$ 170 ' INT 171 ;; 172esac 173case $1 in 174*d*) tst-2 $1 $2; status=$? ;; 175*) $2 -c "tst-2 $1 $2"; status=$? ;; 176esac 177printf '1-%04d\n' $status 178sleep 2 179! 180cat > tst-2 <<'!' 181case $1 in 182*z*) trap ' 183 echo 2-intr 184 exit 0 185 ' INT 186 ;; 187*x*) trap ' 188 echo 2-intr 189 exit 190 ' INT 191 ;; 192*t*) trap ' 193 echo 2-intr 194 trap - INT 195 kill -s INT $$ 196 ' INT 197 ;; 198esac 199case $1 in 200*v*) echo 2-main ;; 201esac 202case $1 in 203*d*) tst-3 $1 $2; status=$? ;; 204*) $2 -c "tst-3 $1 $2"; status=$? ;; 205esac 206printf '2-%04d\n' $status 207! 208cat > tst-3 <<'!' 209case $1 in 210*[xz]*) trap ' 211 sleep 2 212 echo 3-intr 213 exit 0 214 ' INT 215 ;; 216*) trap ' 217 sleep 2 218 echo 3-intr 219 trap - INT 220 kill -s INT $$ 221 ' INT 222 ;; 223esac 224case $1 in 225*v*) echo 3-main ;; 226esac 227sleep 5 228printf '3-%04d\n' $? 229! 230chmod +x tst tst-? 231 232# end standalone test generation 233 234export PATH=$PATH: 235typeset -A expected 236expected[---]="3-intr" 237expected[--d]="3-intr" 238expected[-t-]="3-intr 2-intr 1-intr 1-0258" 239expected[-td]="3-intr 2-intr 1-intr 1-0258" 240expected[x--]="3-intr 2-intr" 241expected[x-d]="3-intr 2-intr" 242expected[xt-]="3-intr 2-intr 1-intr 1-0258" 243expected[xtd]="3-intr 2-intr 1-intr 1-0258" 244expected[z--]="3-intr 2-intr 1-0000" 245expected[z-d]="3-intr 2-intr 1-0000" 246expected[zt-]="3-intr 2-intr 1-intr 1-0000" 247expected[ztd]="3-intr 2-intr 1-intr 1-0000" 248 249tst $SHELL > tst.got 250 251while read ops out 252do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- expected '${expected[$ops]}', got '$out'" 253done < tst.got 254 255float s=$SECONDS 256[[ $($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' 257(( (SECONDS-s) < 4 )) && err_exit 'parent does not wait for child to complete before handling signal' 258((s = SECONDS)) 259[[ $($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' 260(( SECONDS-s < 4 )) && err_exit 'parent completes early' 261 262unset n s t 263for s in $(kill -l) 264do if ! n=$(kill -l $s 2>/dev/null) 265 then err_exit "'kill -l $s' failed" 266 continue 267 fi 268 if ! t=$(kill -l $n 2>/dev/null) 269 then err_exit "'kill -l $n' failed" 270 continue 271 fi 272 if [[ $s == ?(SIG)$t ]] 273 then continue 274 fi 275 if ! m=$(kill -l $t 2>/dev/null) 276 then err_exit "'kill -l $t' failed" 277 continue 278 fi 279 if [[ $m == $n ]] 280 then continue 281 fi 282 err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n" 283done 284yes=$(whence -p yes) 285[[ $yes ]] && for exp in TERM VTALRM PIPE 286do { $SHELL <<- EOF 287 foo() { return 0; } 288 trap foo EXIT 289 { sleep 2; kill -$exp \$\$; sleep 3; kill -0 \$\$ && kill -KILL \$\$; } & 290 $yes | while read yes; do 291 (/bin/date; sleep .1) 292 done > /dev/null 293 EOF 294 } 2>> /dev/null 295 got=$(kill -l $?) 296 [[ $exp == $got ]] || err_exit "kill -$exp \$\$ failed, required termination by signal '$got'" 297done 298 299SECONDS=0 300$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished' > $tmp/sig 301(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" 302x=$(<$tmp/sig) 303[[ $x == done ]] || err_exit "wrong result - execting done got $x" 304(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" 305 306SECONDS=0 307{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit" EXIT; (sleep 5);print finished' > $tmp/sig ;} 2> /dev/null 308[[ $(kill -l $?) == TERM ]] || err_exit "wrong exit status expecting TERM got $(kill -l $?)" 309x=$(<$tmp/sig) 310[[ $x == done ]] || err_exit "wrong result - execting done got $x" 311(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" 312 313SECONDS=0 314x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished') 315(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" 316[[ $x == done ]] || err_exit "wrong result - execting done got $x" 317(( SECONDS < 4 )) && err_exit "took $SECONDS seconds, expecting around 5" 318 319trap '' SIGBUS 320[[ $($SHELL -c 'trap date SIGBUS;trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap' 321trap -- - SIGBUS 322 323exit $((Errors)) 324