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 let Errors+=1 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 34# test basic file operations like redirection, pipes, file expansion 35set -- \ 36 go+r 0000 \ 37 go-r 0044 \ 38 ug=r 0330 \ 39 go+w 0000 \ 40 go-w 0022 \ 41 ug=w 0550 \ 42 go+x 0000 \ 43 go-x 0011 \ 44 ug=x 0660 \ 45 go-rx 0055 \ 46 uo-wx 0303 \ 47 ug-rw 0660 \ 48 o= 0007 49while (( $# >= 2 )) 50do umask 0 51 umask $1 52 g=$(umask) 53 [[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g" 54 shift 2 55done 56umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" 57if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] 58then err_exit 'umask -S incorrect' 59fi 60pwd=$PWD 61[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL 62cd $tmp || { err_exit "cd $tmp failed"; exit 1; } 63um=$(umask -S) 64( umask 0777; > foobar ) 65rm -f foobar 66> foobar 67[[ -r foobar ]] || err_exit 'umask not being restored after subshell' 68umask "$um" 69rm -f foobar 70# optimizer bug test 71> foobar 72for i in 1 2 73do print foobar* 74 rm -f foobar 75done > out 76if [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] 77then print -u2 "optimizer bug with file expansion" 78fi 79rm -f out foobar 80mkdir dir 81if [[ $(print */) != dir/ ]] 82then err_exit 'file expansion with trailing / not working' 83fi 84if [[ $(print *) != dir ]] 85then err_exit 'file expansion with single file not working' 86fi 87print hi > .foo 88if [[ $(print *) != dir ]] 89then err_exit 'file expansion leading . not working' 90fi 91date > dat1 || err_exit "date > dat1 failed" 92test -r dat1 || err_exit "dat1 is not readable" 93x=dat1 94cat <$x > dat2 || err_exit "cat < $x > dat2 failed" 95cat dat1 dat2 | cat | cat | cat > dat3 || err_exit "cat pipe failed" 96cat > dat4 <<! 97$(date) 98! 99cat dat1 dat2 | cat | cat | cat > dat5 & 100wait $! 101set -- dat* 102if (( $# != 5 )) 103then err_exit "dat* matches only $# files" 104fi 105if (command > foo\\abc) 2> /dev/null 106then set -- foo* 107 if [[ $1 != 'foo\abc' ]] 108 then err_exit 'foo* does not match foo\abc' 109 fi 110fi 111if ( : > TT* && : > TTfoo ) 2>/dev/null 112then set -- TT* 113 if (( $# < 2 )) 114 then err_exit 'TT* not expanding when file TT* exists' 115 fi 116fi 117cd ~- || err_exit "cd back failed" 118cat > $tmp/script <<- ! 119 #! $SHELL 120 print -r -- \$0 121! 122chmod 755 $tmp/script 123if [[ $($tmp/script) != "$tmp/script" ]] 124then err_exit '$0 not correct for #! script' 125fi 126bar=foo 127eval foo=\$bar 128if [[ $foo != foo ]] 129then err_exit 'eval foo=\$bar not working' 130fi 131bar='foo=foo\ bar' 132eval $bar 133if [[ $foo != 'foo bar' ]] 134then err_exit 'eval foo=\$bar, with bar="foo\ bar" not working' 135fi 136cd /tmp 137cd ../../tmp || err_exit "cd ../../tmp failed" 138if [[ $PWD != /tmp ]] 139then err_exit 'cd ../../tmp is not /tmp' 140fi 141( sleep 2; cat <<! 142foobar 143! 144) | cat > $tmp/foobar & 145wait $! 146foobar=$( < $tmp/foobar) 147if [[ $foobar != foobar ]] 148then err_exit "$foobar is not foobar" 149fi 150{ 151 print foo 152 /bin/echo bar 153 print bam 154} > $tmp/foobar 155if [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] 156then err_exit "output file pointer not shared correctly" 157fi 158cat > $tmp/foobar <<\! 159 print foo 160 /bin/echo bar 161 print bam 162! 163chmod +x $tmp/foobar 164if [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] 165then err_exit "script not working" 166fi 167if [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] 168then err_exit "script | cat not working" 169fi 170if [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] 171then err_exit "output file pointer not shared correctly" 172fi 173rm -f $tmp/foobar 174x=$( (print foo) ; (print bar) ) 175if [[ $x != $'foo\nbar' ]] 176then err_exit " ( (print foo);(print bar ) failed" 177fi 178x=$( (/bin/echo foo) ; (print bar) ) 179if [[ $x != $'foo\nbar' ]] 180then err_exit " ( (/bin/echo);(print bar ) failed" 181fi 182x=$( (/bin/echo foo) ; (/bin/echo bar) ) 183if [[ $x != $'foo\nbar' ]] 184then err_exit " ( (/bin/echo);(/bin/echo bar ) failed" 185fi 186cat > $tmp/script <<\! 187if [[ -p /dev/fd/0 ]] 188then builtin cat 189 cat - > /dev/null 190 [[ -p /dev/fd/0 ]] && print ok 191else print no 192fi 193! 194chmod +x $tmp/script 195case $( (print) | $tmp/script;:) in 196ok) ;; 197no) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; 198*) err_exit "builtin replaces standard input pipe" ;; 199esac 200print 'print $0' > $tmp/script 201print ". $tmp/script" > $tmp/scriptx 202chmod +x $tmp/scriptx 203if [[ $($tmp/scriptx) != $tmp/scriptx ]] 204then err_exit '$0 not correct for . script' 205fi 206cd $tmp || { err_exit "cd $tmp failed"; exit 1; } 207print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e 208chmod 755 a b c d e 209x=$(./a) 210if [[ $x != "hello there" ]] 211then err_exit "nested scripts failed" 212fi 213x=$( (./a) | cat) 214if [[ $x != "hello there" ]] 215then err_exit "scripts in subshells fail" 216fi 217cd ~- || err_exit "cd back failed" 218x=$( (/bin/echo foo) 2> /dev/null ) 219if [[ $x != foo ]] 220then err_exit "subshell in command substitution fails" 221fi 222exec 9>& 1 223exec 1>&- 224x=$(print hello) 225if [[ $x != hello ]] 226then err_exit "command subsitution with stdout closed failed" 227fi 228exec >& 9 229cd $pwd 230x=$(cat <<\! | $SHELL 231/bin/echo | /bin/cat 232/bin/echo hello 233! 234) 235if [[ $x != $'\n'hello ]] 236then err_exit "$SHELL not working when standard input is a pipe" 237fi 238x=$( (/bin/echo hello) 2> /dev/null ) 239if [[ $x != hello ]] 240then err_exit "subshell in command substitution with 1 closed fails" 241fi 242cat > $tmp/script <<- \! 243read line 2> /dev/null 244print done 245! 246if [[ $($SHELL $tmp/script <&-) != done ]] 247then err_exit "executing script with 0 closed fails" 248fi 249trap '' INT 250cat > $tmp/script <<- \! 251trap 'print bad' INT 252kill -s INT $$ 253print good 254! 255chmod +x $tmp/script 256if [[ $($SHELL $tmp/script) != good ]] 257then err_exit "traps ignored by parent not ignored" 258fi 259trap - INT 260cat > $tmp/script <<- \! 261read line 262/bin/cat 263! 264if [[ $($SHELL $tmp/script <<! 265one 266two 267! 268) != two ]] 269then err_exit "standard input not positioned correctly" 270fi 271word=$(print $'foo\nbar' | { read line; /bin/cat;}) 272if [[ $word != bar ]] 273then err_exit "pipe to { read line; /bin/cat;} not working" 274fi 275word=$(print $'foo\nbar' | ( read line; /bin/cat) ) 276if [[ $word != bar ]] 277then err_exit "pipe to ( read line; /bin/cat) not working" 278fi 279if [[ $(print x{a,b}y) != 'xay xby' ]] 280then err_exit 'brace expansion not working' 281fi 282if [[ $(for i in foo bar 283 do ( tgz=$(print $i) 284 print $tgz) 285 done) != $'foo\nbar' ]] 286then err_exit 'for loop subshell optimizer bug' 287fi 288unset a1 289optbug() 290{ 291 set -A a1 foo bar bam 292 integer i 293 for ((i=0; i < 3; i++)) 294 do 295 (( ${#a1[@]} < 2 )) && return 0 296 set -- "${a1[@]}" 297 shift 298 set -A a1 -- "$@" 299 done 300 return 1 301} 302optbug || err_exit 'array size optimzation bug' 303wait # not running --pipefail which would interfere with subsequent tests 304: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect) 305sleep 20 & 306pids=$! 307if [[ $(jobs -p) != $! ]] 308then err_exit 'jobs -p not reporting a background job' 309fi 310sleep 20 & 311pids="$pids $!" 312foo() 313{ 314 set -- $(jobs -p) 315 (( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected" 316} 317foo 318kill $pids 319 320[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working' 321[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored' 322[[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug' 323command exec 3<> /dev/null 324if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /dev/null 325then [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' 326 [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 327 line0 328 line1 329 line2 330 !!! 331 wait 332 cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' 333 > $tmp/scriptx 334 [[ $($SHELL -c $' 335 for i in 1 336 do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! 337 line0 338 line1 339 line2 340 !!! 341 done 342 wait 343 cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' 344 [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || 345 err_exit 'process substitution of compound commands not working' 346fi 347[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' 348print cat > $tmp/scriptx 349chmod +x $tmp/scriptx 350[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' 351[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' 352[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' 353if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /dev/null 354then [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop" 355 $SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop" 356fi 357exec 3> /dev/null 358print 'print foo "$@"' > $tmp/scriptx 359[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' 360print "#! $SHELL" > $tmp/scriptx 361print 'print -- $0' >> $tmp/scriptx 362chmod +x $tmp/scriptx 363[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" 364cat > $tmp/scriptx <<- \EOF 365 myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} 366 set -o pipefail 367 sleep 3 | myfilter 368EOF 369(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' 370exec 3<&- 371( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' 372$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' 373$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported' 374 x=${ 375 print hello 376 } 377 [[ $x == hello ]] 378EOF 379$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported ' 380 y=bye 381 x=${ 382 y=hello 383 print hello 384 } 385 [[ $y == $x ]] 386EOF 387$SHELL 2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported' 388 x=${ 389 print ${ print hello;} $(print world) 390 } 391 [[ $x == 'hello world' ]] 392EOF 393$SHELL 2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }' 394 x=${ { print -n } ; print -n hello ; } ; print ' world' } 395 [[ $x == '}hello world' ]] 396EOF 397$SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' 398 f() 399 { 400 print foo 401 } 402 [[ ${ f;}bar == foobar ]] 403EOF 404 405unset foo 406[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' 407[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' 408[[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' 409[[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' 410unset foo 411foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false' 412expected=foreback 413got=$(print -n fore; (sleep 2;print back)&) 414[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" 415 416binfalse=$(whence -p false) 417for false in false $binfalse 418do x=$($false) && err_exit "x=\$($false) should fail" 419 $($false) && err_exit "\$($false) should fail" 420 $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" 421done 422if env x-a=y >/dev/null 2>&1 423then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' 424fi 425float s=SECONDS 426sleep=$(whence -p sleep) 427for i in 1 2 428do print $i 429done | while read sec; do ( $sleep $sec; $sleep $sec) done 430(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' 431s=SECONDS 432set -o pipefail 433for ((i=0; i < 30; i++)) 434do print hello 435 sleep .1 436done | $sleep 1 437(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' 438[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' 439var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) 440[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' 441 442exp= 443got=$( 444 function fun 445 { 446 $binfalse && echo FAILED 447 } 448 : works if this line deleted : | 449 fun 450 : works if this line deleted : 451) 452[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" 453got=$( 454 : works if this line deleted : | 455 { $binfalse && echo FAILED; } 456 : works if this line deleted : 457) 458[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" 459 460got=$( 461 : works if this line deleted : | 462 ( $binfalse && echo FAILED ) 463 : works if this line deleted : 464) 465[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" 466 467( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' 468 469bintrue=$(whence -p true) 470set -o pipefail 471float start=$SECONDS end 472for ((i=0; i < 2; i++)) 473do print foo 474 sleep 1.5 475done | { read; $bintrue; end=$SECONDS ;} 476(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish" 477set +o pipefail 478(( (SECONDS-end) > 2 )) && err_exit "pipefail causing $bintrue to wait for other end of pipe" 479 480 481{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails" 482 483if [[ $bintrue ]] 484then float t0=SECONDS 485 { time sleep 1.5 | $bintrue ;} 2> /dev/null 486 (( (SECONDS-t0) < 1 )) && err_exit 'time not waiting for pipeline to complete' 487fi 488 489cat > $tmp/foo.sh <<- \EOF 490 eval "cat > /dev/null < /dev/null" 491 sleep 1 492EOF 493float sec=SECONDS 494. $tmp/foo.sh | cat > /dev/null 495(( (SECONDS-sec) < .7 )) && err_exit '. script does not restore output redirection with eval' 496 497file=$tmp/foobar 498builtin cat 499for ((n=0; n < 1000; n++)) 500do 501 > $file 502 { sleep .001;echo $? >$file;} | cat > /dev/null 503 if [[ ! -s $file ]] 504 then err_exit 'output from pipe is lost with pipe to builtin' 505 break; 506 fi 507done 508 509$SHELL -c 'kill -0 123456789123456789123456789' 2> /dev/null && err_exit 'kill not catching process id overflows' 510 511[[ $($SHELL -c '{ cd..; print ok;}' 2> /dev/null) == ok ]] || err_exit 'command name ending in .. causes shell to abort' 512 513$SHELL -xc '$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH exec $SHELL -c :)' > /dev/null 2>&1 || err_exit "ksh -xc '(name=value exec ksh)' fails with err=$?" 514 515$SHELL 2> /dev/null -c $'for i;\ndo :;done' || err_exit 'for i ; <newline> not vaid' 516 517# The time keyword should obey the errexit option 518# https://www.illumos.org/issues/7694 519time_errexit="$tmp/time_errexit.sh" 520cat > "$time_errexit" << 'EOF' 521time false 522echo FAILURE 523true 524EOF 525got=$($SHELL -e "$time_errexit" 2>&1) 526(( $? == 0 )) && err_exit "The time keyword ignores the errexit option" \ 527 "(got $(printf %q "$got"))" 528[[ -z $got ]] || err_exit "The time keyword produces output when a timed command fails and the errexit option is on" \ 529 "(got $(printf %q "$got"))" 530 531exit $((Errors<125?Errors:125)) 532