1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2012 AT&T Intellectual Property # 5# and is licensed under the # 6# Eclipse Public License, Version 1.0 # 7# by AT&T Intellectual Property # 8# # 9# A copy of the License is available at # 10# http://www.eclipse.org/org/documents/epl-v10.html # 11# (with md5 checksum b35adb5213ca9657e911e9befb180842) # 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 36unset n s t 37typeset -A SIG 38for s in $(kill -l) 39do if ! n=$(kill -l $s 2>/dev/null) 40 then err_exit "'kill -l $s' failed" 41 elif ! t=$(kill -l $n 2>/dev/null) 42 then err_exit "'kill -l $n' failed" 43 elif [[ $s == ?(SIG)$t ]] 44 then SIG[${s#SIG}]=1 45 elif ! m=$(kill -l $t 2>/dev/null) 46 then err_exit "'kill -l $t' failed" 47 elif [[ $m != $n ]] 48 then err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n" 49 fi 50done 51 52( 53 set --pipefail 54 { 55 $SHELL 2> out2 <<- \EOF 56 g=false 57 trap 'print -u2 PIPED; $g && exit 0;g=true' PIPE 58 while : 59 do print hello 60 done 61 EOF 62 } | head > /dev/null 63 (( $? == 0)) || err_exit "SIGPIPE with wrong error code $?" 64 [[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct' 65) & 66cop=$! 67{ sleep 4; kill $cop; } 2>/dev/null & 68spy=$! 69if wait $cop 2>/dev/null 70then kill $spy 2>/dev/null 71else err_exit "pipe with --pipefail PIPE trap hangs" 72fi 73wait 74rm -f out2 75 76[[ $( trap 'print -n got_child' SIGCHLD 77 sleep 2 & 78 for ((i=0; i < 4; i++)) 79 do sleep .75 80 print -n $i 81 done) == 01got_child23 ]] || err_exit 'SIGCHLD not working' 82 83# begin standalone SIGINT test generation 84 85cat > tst <<'!' 86# shell trap tests 87# 88# tst control script that calls tst-1, must be run by ksh 89# tst-1 calls tst-2 90# tst-2 calls tst-3 91# tst-3 defaults or handles and discards/propagates SIGINT 92# 93# initial -v option lists script entry and SIGINT delivery 94# 95# three test options 96# 97# d call next script directly, otherwise via $SHELL -c 98# t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x 99# x trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit, otherwise SIGINT default 100# z trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit 0, otherwise SIGINT default 101# 102# Usage: tst [-v] [-options] shell-to-test ... 103 104# "trap + sig" is an unadvertized extension for this test 105# if run from nmake SIGINT is set to SIG_IGN 106# this call sets it back to SIG_DFL 107# semantics w.r.t. function scope must be worked out before 108# making it public 109trap + INT 110 111set -o monitor 112 113function gen 114{ 115 typeset o t x d 116 for x in - x z 117 do case $x in 118 [$1]) for t in - t 119 do case $t in 120 [$1]) for d in - d 121 do case $d in 122 [$1]) o="$o $x$t$d" 123 esac 124 done 125 esac 126 done 127 esac 128 done 129 echo '' $o 130} 131 132case $1 in 133-v) v=v; shift ;; 134-*v*) v=v ;; 135*) v= ;; 136esac 137case $1 in 138*' '*) o=$1; shift ;; 139-*) o=$(gen $1); shift ;; 140*) o=$(gen -txd) ;; 141esac 142case $# in 1430) set ksh bash ksh88 pdksh ash zsh ;; 144esac 145for f in $o 146do case $# in 147 1) ;; 148 *) echo ;; 149 esac 150 for sh 151 do if $sh -c 'exit 0' > /dev/null 2>&1 152 then case $# in 153 1) printf '%3s ' "$f" ;; 154 *) printf '%16s %3s ' "$sh" "$f" ;; 155 esac 156 $sh tst-1 $v$f $sh > tst.out & 157 wait 158 echo $(cat tst.out) 159 fi 160 done 161done 162case $# in 1631) ;; 164*) echo ;; 165esac 166! 167cat > tst-1 <<'!' 168exec 2>/dev/null 169case $1 in 170*v*) echo 1-main ;; 171esac 172{ 173 sleep 2 174 case $1 in 175 *v*) echo "SIGINT" ;; 176 esac 177 kill -s INT 0 178} & 179case $1 in 180*t*) trap ' 181 echo 1-intr 182 trap - INT 183 # omitting the self kill exposes shells that deliver 184 # the SIGINT trap but exit 0 for -xt 185 # kill -s INT $$ 186 ' INT 187 ;; 188esac 189case $1 in 190*d*) tst-2 $1 $2; status=$? ;; 191*) $2 -c "tst-2 $1 $2"; status=$? ;; 192esac 193printf '1-%04d\n' $status 194sleep 2 195! 196cat > tst-2 <<'!' 197case $1 in 198*z*) trap ' 199 echo 2-intr 200 exit 0 201 ' INT 202 ;; 203*x*) trap ' 204 echo 2-intr 205 exit 206 ' INT 207 ;; 208*t*) trap ' 209 echo 2-intr 210 trap - INT 211 kill -s INT $$ 212 ' INT 213 ;; 214esac 215case $1 in 216*v*) echo 2-main ;; 217esac 218case $1 in 219*d*) tst-3 $1 $2; status=$? ;; 220*) $2 -c "tst-3 $1 $2"; status=$? ;; 221esac 222printf '2-%04d\n' $status 223! 224cat > tst-3 <<'!' 225case $1 in 226*[xz]*) trap ' 227 sleep 2 228 echo 3-intr 229 exit 0 230 ' INT 231 ;; 232*) trap ' 233 sleep 2 234 echo 3-intr 235 trap - INT 236 kill -s INT $$ 237 ' INT 238 ;; 239esac 240case $1 in 241*v*) echo 3-main ;; 242esac 243sleep 5 244printf '3-%04d\n' $? 245! 246chmod +x tst tst-? 247 248# end standalone test generation 249 250export PATH=$PATH: 251typeset -A expected 252expected[---]="3-intr" 253expected[--d]="3-intr" 254expected[-t-]="3-intr 2-intr 1-intr 1-0258" 255expected[-td]="3-intr 2-intr 1-intr 1-0258" 256expected[x--]="3-intr 2-intr 1-0000" 257expected[x-d]="3-intr 2-intr 1-0000" 258expected[xt-]="3-intr 2-intr 1-intr 1-0000" 259expected[xtd]="3-intr 2-intr 1-intr 1-0000" 260expected[z--]="3-intr 2-intr 1-0000" 261expected[z-d]="3-intr 2-intr 1-0000" 262expected[zt-]="3-intr 2-intr 1-intr 1-0000" 263expected[ztd]="3-intr 2-intr 1-intr 1-0000" 264 265tst $SHELL > tst.got 266 267while read ops out 268do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- expected '${expected[$ops]}', got '$out'" 269done < tst.got 270 271if [[ ${SIG[USR1]} ]] 272then float s=$SECONDS 273 [[ $(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' 274 (( (SECONDS-s) < 4 )) && err_exit 'parent does not wait for child to complete before handling signal' 275 ((s = SECONDS)) 276 [[ $(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' 277 (( SECONDS-s < 4 )) && err_exit 'parent completes early' 278fi 279 280yes=$(whence -p yes) 281if [[ $yes ]] 282then for exp in TERM VTALRM PIPE 283 do if [[ ${SIG[$exp]} ]] 284 then { 285 $SHELL <<- EOF 286 foo() { return 0; } 287 trap foo EXIT 288 { sleep 2; kill -$exp \$\$; sleep 3; kill -0 \$\$ && kill -KILL \$\$; } & 289 $yes | 290 while read yes 291 do (/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'" 297 fi 298 done 299fi 300 301SECONDS=0 302$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished' > $tmp/sig 303e=$? 304[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 305x=$(<$tmp/sig) 306[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 307(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 308 309SECONDS=0 310$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished' > $tmp/sig 311e=$? 312[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 313x=$(<$tmp/sig) 314[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 315(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 316 317SECONDS=0 318{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished' > $tmp/sig ;} 2> /dev/null 319e=$? 320[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 321x=$(<$tmp/sig) 322[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 323(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 324 325SECONDS=0 326{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished' > $tmp/sig ;} 2> /dev/null 327e=$? 328[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 329x=$(<$tmp/sig) 330[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 331(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 332 333SECONDS=0 334x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished') 335e=$? 336[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 337[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 338(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 339 340SECONDS=0 341x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished') 342e=$? 343[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" 344[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" 345(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" 346 347trap '' SIGBUS 348[[ $($SHELL -c 'trap date SIGBUS; trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap' 349trap -- - SIGBUS 350 351{ 352 x=$( 353 $SHELL <<- \++EOF 354 timeout() 355 { 356 trap 'trap - TERM; return' TERM 357 ( sleep $1; kill -TERM $$ ) >/dev/null 2>&1 & 358 sleep 3 359 } 360 timeout 1 361 print ok 362++EOF 363 ) 364} 2> /dev/null 365[[ $x == ok ]] || err_exit 'return without arguments in trap not preserving exit status' 366 367x=$( 368 $SHELL <<- \++EOF 369 set -o pipefail 370 foobar() 371 { 372 for ((i=0; i < 10000; i++)) 373 do print abcdefghijklmnopqrstuvwxyz 374 done | head > /dev/null 375 } 376 foobar 377 print ok 378 ++EOF 379) 380[[ $x == ok ]] || err_exit 'SIGPIPE exit status causes PIPE signal to be propogaged' 381 382x=$( 383 $SHELL <<- \EOF 384 trap "print GNAW" URG 385 print 1 386 ( sleep 1 ; kill -URG $$ ; sleep 1 ; print S1 ; ) 387 print 2 388EOF 389) 390[[ $x == $'1\nS1\nGNAW\n2' ]] || err_exit 'signal ignored in subshell not propagated to parent' 391 392if [[ ${SIG[RTMIN]} ]] 393then { 394 $SHELL <<- \EOF 395 trap : RTMIN 396 for ((i=0 ; i < 3 ; i++)) 397 do sleep 1 398 kill -RTMIN $$ 2> /dev/null 399 done & 400 wait 401 EOF 402 } 2> /dev/null 403 [[ $? == 0 ]] && err_exit 'wait interrupted by caught signal should have non-zero exit status' 404 { 405 $SHELL <<- \EOF 406 for ((i=0 ; i < 3 ; i++)) 407 do sleep 1 408 kill -RTMIN $$ 2> /dev/null 409 done & 410 wait 411 EOF 412 } 2> /dev/null 413 [[ $(kill -l $?) == RTMIN ]] || err_exit 'wait interrupted by signal not caught should exit with the value of that signal+256' 414fi 415 416function b 417{ 418 sleep 3 419 endb=1 420} 421 422function a 423{ 424 trap 'print int' TERM 425 b 426 enda=1 427} 428 429{ /bin/sleep 1;kill -s TERM $$;}& 430unset enda endb 431a 432[[ $endb ]] && err_exit 'TERM signal did not kill function b' 433[[ $enda == 1 ]] || err_exit 'TERM signal killed function a' 434 435exit $((Errors<125?Errors:125)) 436