diff options
Diffstat (limited to 'usr/src/lib/libshell/common/tests')
79 files changed, 5420 insertions, 973 deletions
diff --git a/usr/src/lib/libshell/common/tests/README.tests b/usr/src/lib/libshell/common/tests/README.tests new file mode 100644 index 0000000000..c78d32d9b1 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/README.tests @@ -0,0 +1,53 @@ + +#### ksh93 test suite + +## Intro +The directory /usr/demo/ksh/tests/ contains the ksh93 test suite +which is used to verify the correct behaviour of ksh93. + +The test suite is split into modules with the ending *.sh +and a frontend called "shtests" which is used to run the tests. + + +## Basic description: +/usr/demo/ksh/tests/shtests <options> <varname=value> <testmodule> + +<options> may be: + -a execute test module one time as normal script code + and a 2nd time as compiled shell script. The env + variable SHCOMP defines the version of the shell + compiler being used (default is "${SHELL%/*}/shcomp", + however it is recommended to explicitly set SHCOMP + to /usr/bin/shcomp). + -c execute test module as compiled shell script + -s execute test module as normal shell script + -t do not print timing information + -v use VMDEBUG +<varname=value> + Sets one or more environment variables to value "value". +<testmodule> + file name of test module + + +## Basic usage in Solaris >= 11 and OpenSolaris/Indiana: +The tests can be executed like this: +$ export SHELL=<path-to-ksh93-executable> +$ export SHCOMP=/usr/bin/shcomp +for t in /usr/demo/ksh/tests/*.sh ; do + $SHELL /usr/demo/ksh/tests/shtests -a "$t" +done + +Note that you MUST NOT use "/usr/bin/ksh93" as value for +SHELL since /usr/bin/ksh93 on Solaris is a wrapper which +selects a suitable executable in /usr/bin/<isa>/ksh93 +based on the hardware capabilities defined via /usr/bin/isalist + +Valid values for SHELL are: +- SHELL=/usr/bin/i86/ksh93 # 32bit i386 +- SHELL=/usr/bin/amd64/ksh93 # 64bit AMD64 +- SHELL=/usr/bin/sparcv7/ksh93 # 32bit SPARC +- SHELL=/usr/bin/sparcv9/ksh93 # 64bit SPARC +- SHELL=/usr/bin/s390/ksh93 # 32bit SystemZ +- SHELL=/usr/bin/s390x/ksh93 # 64bit SystemZ + +# EOF. diff --git a/usr/src/lib/libshell/common/tests/alias.sh b/usr/src/lib/libshell/common/tests/alias.sh index e001668ef7..f527faf23e 100644 --- a/usr/src/lib/libshell/common/tests/alias.sh +++ b/usr/src/lib/libshell/common/tests/alias.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + alias foo='print hello' if [[ $(foo) != hello ]] then err_exit 'foo, where foo is alias for "print hello" failed' @@ -66,7 +70,7 @@ alias !!=print if [[ $(!! hello 2>/dev/null) != hello ]] then err_exit 'alias for !!=print not working' fi -alias foo=echo +alias foo=echo if [[ $(print "$(foo bar)" ) != bar ]] then err_exit 'alias in command substitution not working' fi @@ -81,14 +85,12 @@ then [[ ! $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not set' [[ $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not cleared' fi if hash -r 2>/dev/null && [[ ! $(hash) ]] -then mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" - trap "cd /; rm -rf /tmp/ksh$$" EXIT - PATH=/tmp/ksh$$:/bin:/usr/bin +then PATH=$tmp:/bin:/usr/bin for i in foo -foo -- - do print ':' > /tmp/ksh$$/$i - chmod +x /tmp/ksh$$/$i + do print ':' > $tmp/$i + chmod +x $tmp/$i hash -r -- $i 2>/dev/null || err_exit "hash -r -- $i failed" - [[ $(hash) == $i=/tmp/ksh$$/$i ]] || err_exit "hash -r -- $i failed, expected $i=/tmp/ksh$$/$i, got $(hash)" + [[ $(hash) == $i=$tmp/$i ]] || err_exit "hash -r -- $i failed, expected $i=$tmp/$i, got $(hash)" done else err_exit 'hash -r failed' fi diff --git a/usr/src/lib/libshell/common/tests/append.sh b/usr/src/lib/libshell/common/tests/append.sh index 00c432520a..d3e10c9100 100644 --- a/usr/src/lib/libshell/common/tests/append.sh +++ b/usr/src/lib/libshell/common/tests/append.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/arith.sh b/usr/src/lib/libshell/common/tests/arith.sh index c330abce90..47c9619c75 100644 --- a/usr/src/lib/libshell/common/tests/arith.sh +++ b/usr/src/lib/libshell/common/tests/arith.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -26,8 +26,13 @@ function err_exit alias err_exit='err_exit $LINENO' Command=${0##*/} -trap '' FPE # NOTE: osf.alpha requires this (no ieee math) integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +trap '' FPE # NOTE: osf.alpha requires this (no ieee math) + integer x=1 y=2 z=3 if (( 2+2 != 4 )) then err_exit 2+2!=4 @@ -135,7 +140,7 @@ if [[ $? == 0 ]] then err_exit 'floating point allowed with % operator' fi x=.125 -if [[ $(( 4 * x/2 )) != 0.25 ]] +if [[ $(( 4 * x/2 )) != 0.25 ]] then err_exit '(( 4 * x/2 )) is not 0.25, with x=.125' fi if [[ $(( pow(2,3) )) != 8 ]] @@ -190,7 +195,7 @@ then err_exit "&= not working" fi function newscope { - float x=1.5 + float x=1.5 (( x += 1 )) print -r -- $x } @@ -342,7 +347,7 @@ for ((i=0; i < 4; i++)) do (( ipx = ip % 256 )) (( ip /= 256 )) (( ipx != hex[3-i] )) && err_exit "hex digit $((3-i)) not correct" -done +done unset x x=010 (( x == 8 )) || err_exit 'leading zeros not treated as octal arithmetic' @@ -365,8 +370,7 @@ i=2 unset i; typeset -i i=01-2 (( i == -1 )) || err_exit "01-2 is not -1" -trap 'rm -f /tmp/script$$ /tmp/data$$.[12]' EXIT -cat > /tmp/script$$ <<-\! +cat > $tmp/script <<-\! tests=$* typeset -A blop function blop.get @@ -412,14 +416,14 @@ function mkobj } mkobj bla ! -chmod +x /tmp/script$$ -[[ $(/tmp/script$$ 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' -[[ $(/tmp/script$$ 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +chmod +x $tmp/script +[[ $($tmp/script 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' unset foo typeset -F1 foo=123456789.19 [[ $foo == 123456789.2 ]] || err_exit 'typeset -F1 not working correctly' @@ -434,7 +438,7 @@ for expr in '1/(1.0/2)' '1/(1/2.0)' do [[ $( ( $SHELL -c "( print -r -- \$(($expr)) )" ) 2>/dev/null ) == 2 ]] || err_exit "invalid value for: $expr" done [[ $((5||0)) == 1 ]] || err_exit '$((5||0))'" == $((5||0)) should be 1" -$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7 && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working' +$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7 && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working' $SHELL -c 'b=0; [[ $((b?a=1:b=9)) == 9 ]]' 2> /dev/null || err_exit 'b?a=1:b=9 not working' unset x (( x = 4*atan(1.0) )) @@ -483,4 +487,46 @@ $SHELL -c '(( x=));:' 2> /dev/null && err_exit '((x=)) should be an error' $SHELL -c '(( x+=));:' 2> /dev/null && err_exit '((x+=)) should be an error' $SHELL -c '(( x=+));:' 2> /dev/null && err_exit '((x=+)) should be an error' $SHELL -c 'x=();x.arr[0]=(z=3); ((x.arr[0].z=2))' 2> /dev/null || err_exit '(((x.arr[0].z=2)) should not be an error' + +float t +typeset a b r +v="-0.0 0.0 +0.0 -1.0 1.0 +1.0" +for a in $v +do for b in $v + do (( r = copysign(a,b) )) + (( t = copysign(a,b) )) + [[ $r == $t ]] || err_exit $(printf "float t=copysign(%3.1f,%3.1f) => %3.1f -- expected %3.1f\n" a b t r) + done +done + +typeset -l y y_ascii +(( y=sin(90) )) +y_ascii=$y +(( y == y_ascii )) || err_exit "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" y_ascii)" + +( $SHELL <<- \EOF + p=5 + t[p]=6 + while (( t[p] != 0 )) ; do + (( + p+=1 , + t[p]+=2 , + p+=3 , + t[p]+=5 , + p+=1 , + t[p]+=2 , + p+=1 , + t[p]+=1 , + p-=6 , + t[p]-=1 + )) + : + done +EOF) 2> /dev/null || err_exit 'error with comma expression' + +N=(89551 89557) +i=0 j=1 +[[ $(printf "%d" N[j]-N[i]) == 6 ]] || err_exit 'printf %d N[i]-N[j] failed' +[[ $((N[j]-N[i])) == 6 ]] || err_exit '$((N[j]-N[i])) incorrect' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/arrays.sh b/usr/src/lib/libshell/common/tests/arrays.sh index 14504edc00..996101409f 100644 --- a/usr/src/lib/libshell/common/tests/arrays.sh +++ b/usr/src/lib/libshell/common/tests/arrays.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function fun { integer i @@ -34,8 +40,6 @@ function fun done } -Command=${0##*/} -integer Errors=0 set -A x zero one two three four 'five six' if [[ $x != zero ]] then err_exit '$x is not element 0' @@ -268,7 +272,7 @@ fi export foo typeset -i foo [[ $($SHELL -c "print $foo") == 143 ]]' -) 2> /dev/null || +) 2> /dev/null || err_exit 'exporting associative array not exporting 0-th element' unset foo typeset -A foo @@ -283,7 +287,7 @@ for i in one three four five do : ${foo[$i]} done if [[ ${!foo[@]} != two ]] -then err_exit 'Error in subscript names' +then err_exit 'error in subscript names' fi unset x x=( 1 2 3) @@ -329,24 +333,23 @@ bam[foo]=value [[ $bam == value ]] && err_exit 'unset associative array element error' : only first element of an array can be exported unset bam -trap 'rm -f /tmp/sharr$$' EXIT -print 'print ${var[0]} ${var[1]}' > /tmp/sharr$$ -chmod +x /tmp/sharr$$ -[[ $($SHELL -c "var=(foo bar);export var;/tmp/sharr$$") == foo ]] || err_exit 'export array not exporting just first element' +print 'print ${var[0]} ${var[1]}' > $tmp/script +chmod +x $tmp/script +[[ $($SHELL -c "var=(foo bar);export var;$tmp/script") == foo ]] || err_exit 'export array not exporting just first element' unset foo set -o allexport foo=one foo[1]=two foo[0]=three [[ $foo == three ]] || err_exit 'export all not working with arrays' -cat > /tmp/sharr$$ <<- \! +cat > $tmp/script <<- \! typeset -A foo print foo${foo[abc]} ! # 04-05-24 bug fix unset foo -[[ $($SHELL -c "typeset -A foo;/tmp/sharr$$") == foo ]] 2> /dev/null || err_exit 'empty associative arrays not being cleared correctly before scripts' -[[ $($SHELL -c "typeset -A foo;foo[abc]=abc;/tmp/sharr$$") == foo ]] 2> /dev/null || err_exit 'associative arrays not being cleared correctly before scripts' +[[ $($SHELL -c "typeset -A foo;$tmp/script") == foo ]] 2> /dev/null || err_exit 'empty associative arrays not being cleared correctly before scripts' +[[ $($SHELL -c "typeset -A foo;foo[abc]=abc;$tmp/script") == foo ]] 2> /dev/null || err_exit 'associative arrays not being cleared correctly before scripts' unset foo foo=(one two) [[ ${foo[@]:1} == two ]] || err_exit '${foo[@]:1} == two' @@ -406,7 +409,7 @@ x=${bar[$foo[5]]} test_array[3]=4 print "val=${test_array[3]}" ++EOF+++ -) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' +) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' [[ $($SHELL <<- \+++EOF+++ pastebin=( typeset -a form) pastebin.form+=( name="name" data="clueless" ) @@ -464,4 +467,10 @@ a[6]=six [[ ${a[-1]} == six ]] || err_exit 'a[-1] should be six' [[ ${a[-3]} == four ]] || err_exit 'a[-3] should be four' [[ ${a[-3..-1]} == 'four six' ]] || err_exit "a[-3,-1] should be 'four six'" + +FILTER=(typeset scope) +FILTER[0].scope=include +FILTER[1].scope=exclude +[[ ${#FILTER[@]} == 2 ]] || err_exit "FILTER array should have two elements not ${#FILTER[@]}" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/arrays2.sh b/usr/src/lib/libshell/common/tests/arrays2.sh index 56bce796ae..ee8f0ae315 100644 --- a/usr/src/lib/libshell/common/tests/arrays2.sh +++ b/usr/src/lib/libshell/common/tests/arrays2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/attributes.sh b/usr/src/lib/libshell/common/tests/attributes.sh index 2d4f1e3d21..474972c03b 100644 --- a/usr/src/lib/libshell/common/tests/attributes.sh +++ b/usr/src/lib/libshell/common/tests/attributes.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + r=readonly u=Uppercase l=Lowercase i=22 i8=10 L=abc L5=def uL5=abcdef xi=20 x=export t=tagged H=hostname LZ5=026 RZ5=026 Z5=123 lR5=ABcdef R5=def n=l for option in u l i i8 L L5 LZ5 RZ5 Z5 r x H t R5 uL5 lR5 xi n @@ -115,18 +119,18 @@ fi sz=(typeset -E y=2.2) string="$(print $sz)" if [[ "${sz}" == *'typeset -E -F'* ]] -then err_exit 'print of exponential shows both -E and -F attributes' +then err_exit 'print of exponential shows both -E and -F attributes' fi -print 'typeset -i m=48/4+1;print -- $m' > /tmp/ksh$$ -chmod +x /tmp/ksh$$ +print 'typeset -i m=48/4+1;print -- $m' > $tmp/script +chmod +x $tmp/script typeset -Z2 m -if [[ $(/tmp/ksh$$) != 13 ]] +if [[ $($tmp/script) != 13 ]] then err_exit 'attributes not cleared for script execution' fi -print 'print VAR=$VAR' > /tmp/ksh$$ +print 'print VAR=$VAR' > $tmp/script typeset -L70 VAR=var -/tmp/ksh$$ > /tmp/ksh$$.1 -[[ $(< /tmp/ksh$$.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' +$tmp/script > $tmp/script.1 +[[ $(< $tmp/script.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' typeset -Z LAST=00 unset -f foo function foo @@ -145,7 +149,6 @@ if (( ${#LAST} != 2 )) then err_exit 'LAST!=2' fi [[ $(set | grep LAST) == LAST=02 ]] || err_exit "LAST not correct in set list" -rm -rf /tmp/ksh$$* set -a unset foo foo=bar @@ -195,7 +198,9 @@ hello worldhello worldhello world ! [[ $v1 == "$b1" ]] || err_exit "v1=$v1 should be $b1" [[ $v2 == "$x" ]] || err_exit "v1=$v2 should be $x" -[[ $(env - '!=1' $SHELL -c 'echo ok' 2>/dev/null) == ok ]] || err_exit 'malformed environment terminates shell' +if env '!=1' >/dev/null 2>&1 +then [[ $(env '!=1' $SHELL -c 'echo ok' 2>/dev/null) == ok ]] || err_exit 'malformed environment terminates shell' +fi unset var typeset -b var printf '12%Z34' | read -r -N 5 var @@ -211,10 +216,10 @@ unset foo bar unset -f fun function fun { - export foo=hello + export foo=hello typeset -x bar=world [[ $foo == hello ]] || err_exit 'export scoping problem in function' -} +} fun [[ $(export | grep foo) == 'foo=hello' ]] || err_exit 'export not working in functions' [[ $(export | grep bar) ]] && err_exit 'typeset -x not local' @@ -224,9 +229,9 @@ fred[66]=88 unset x y z typeset -LZ3 x=abcd y z=00abcd y=03 -[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' -[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' -[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' +[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' unset x z set +a [[ $(typeset -p z) ]] && err_exit "typeset -p for z undefined failed" @@ -280,4 +285,43 @@ function foo } bar=xxx [[ $(foo) == bar=xxx ]] || err_exit 'typeset -p not working inside a function' +unset foo +typeset -L5 foo +[[ $(typeset -p foo) == 'typeset -L 5 foo' ]] || err_exit 'typeset -p not working for variables with attributes but without a value' +{ $SHELL <<- EOF + typeset -L3 foo=aaa + typeset -L6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} || err_exit 'typeset -L should not preserve old attributes' +{ $SHELL <<- EOF + typeset -R3 foo=aaa + typeset -R6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} 2> /dev/null || err_exit 'typeset -R should not preserve old attributes' + +expected='YWJjZGVmZ2hpag==' +unset foo +typeset -b -Z10 foo +read foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -Z10 foo +read -N10 foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -A foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -A" foo not working' +unset foo +typeset -b -a foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -a" foo not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary associative array element not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary indexed array element not working' +unset foo + +$SHELL 2> /dev/null -c 'export foo=(bar=3)' && err_exit 'compound variables cannot be exported' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/basic.sh b/usr/src/lib/libshell/common/tests/basic.sh index 3911f9c472..597833e74f 100644 --- a/usr/src/lib/libshell/common/tests/basic.sh +++ b/usr/src/lib/libshell/common/tests/basic.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,9 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test basic file operations like redirection, pipes, file expansion Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test basic file operations like redirection, pipes, file expansion set -- \ go+r 0000 \ go-r 0044 \ @@ -53,11 +57,9 @@ umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] then err_exit 'umask -S incorrect' fi -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap "cd /; rm -rf /tmp/ksh$$" EXIT pwd=$PWD [[ $SHELL != /* ]] && SHELL=$pwd/$SHELL -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } um=$(umask -S) ( umask 0777; > foobar ) rm -f foobar @@ -70,11 +72,11 @@ rm -f foobar for i in 1 2 do print foobar* rm -f foobar -done > out$$ -if [[ "$(<out$$)" != "foobar"$'\n'"foobar*" ]] +done > out +if [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] then print -u2 "optimizer bug with file expansion" fi -rm -f out$$ foobar +rm -f out foobar mkdir dir if [[ $(print */) != dir/ ]] then err_exit 'file expansion with trailing / not working' @@ -100,7 +102,7 @@ set -- dat* if (( $# != 5 )) then err_exit "dat* matches only $# files" fi -if (command > foo\\abc) 2> /dev/null +if (command > foo\\abc) 2> /dev/null then set -- foo* if [[ $1 != 'foo\abc' ]] then err_exit 'foo* does not match foo\abc' @@ -113,15 +115,14 @@ then set -- TT* fi fi cd ~- || err_exit "cd back failed" -cat > /tmp/ksh$$/script <<- ! +cat > $tmp/script <<- ! #! $SHELL print -r -- \$0 ! -chmod 755 /tmp/ksh$$/script -if [[ $(/tmp/ksh$$/script) != "/tmp/ksh$$/script" ]] +chmod 755 $tmp/script +if [[ $($tmp/script) != "$tmp/script" ]] then err_exit '$0 not correct for #! script' fi -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" bar=foo eval foo=\$bar if [[ $foo != foo ]] @@ -140,9 +141,9 @@ fi ( sleep 2; cat <<! foobar ! -) | cat > /tmp/foobar$$ & +) | cat > $tmp/foobar & wait $! -foobar=$( < /tmp/foobar$$) +foobar=$( < $tmp/foobar) if [[ $foobar != foobar ]] then err_exit "$foobar is not foobar" fi @@ -150,26 +151,26 @@ fi print foo /bin/echo bar print bam -} > /tmp/foobar$$ -if [[ $( < /tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Output file pointer not shared correctly." +} > $tmp/foobar +if [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" fi -cat > /tmp/foobar$$ <<\! +cat > $tmp/foobar <<\! print foo /bin/echo bar print bam ! -chmod +x /tmp/foobar$$ -if [[ $(/tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Script not working." +chmod +x $tmp/foobar +if [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "script not working" fi -if [[ $(/tmp/foobar$$ | /bin/cat) != $'foo\nbar\nbam' ]] -then err_exit "Script | cat not working." +if [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] +then err_exit "script | cat not working" fi -if [[ $( /tmp/foobar$$) != $'foo\nbar\nbam' ]] -then err_exit "Output file pointer not shared correctly." +if [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" fi -rm -f /tmp/foobar$$ +rm -f $tmp/foobar x=$( (print foo) ; (print bar) ) if [[ $x != $'foo\nbar' ]] then err_exit " ( (print foo);(print bar ) failed" @@ -182,7 +183,7 @@ x=$( (/bin/echo foo) ; (/bin/echo bar) ) if [[ $x != $'foo\nbar' ]] then err_exit " ( (/bin/echo);(/bin/echo bar ) failed" fi -cat > /tmp/ksh$$ <<\! +cat > $tmp/script <<\! if [[ -p /dev/fd/0 ]] then builtin cat cat - > /dev/null @@ -190,33 +191,30 @@ then builtin cat else print no fi ! -chmod +x /tmp/ksh$$ -case $( (print) | /tmp/ksh$$;:) in +chmod +x $tmp/script +case $( (print) | $tmp/script;:) in ok) ;; no) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; *) err_exit "builtin replaces standard input pipe" ;; esac -print 'print $0' > /tmp/ksh$$ -print ". /tmp/ksh$$" > /tmp/ksh$$x -chmod +x /tmp/ksh$$x -if [[ $(/tmp/ksh$$x) != /tmp/ksh$$x ]] +print 'print $0' > $tmp/script +print ". $tmp/script" > $tmp/scriptx +chmod +x $tmp/scriptx +if [[ $($tmp/scriptx) != $tmp/scriptx ]] then err_exit '$0 not correct for . script' fi -rm -r /tmp/ksh$$ /tmp/ksh$$x -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" -print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } +print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e chmod 755 a b c d e x=$(./a) if [[ $x != "hello there" ]] -then err_exit "nested scripts failed" +then err_exit "nested scripts failed" fi x=$( (./a) | cat) if [[ $x != "hello there" ]] -then err_exit "scripts in subshells fail" +then err_exit "scripts in subshells fail" fi cd ~- || err_exit "cd back failed" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" x=$( (/bin/echo foo) 2> /dev/null ) if [[ $x != foo ]] then err_exit "subshell in command substitution fails" @@ -239,29 +237,29 @@ x=$( (/bin/echo hello) 2> /dev/null ) if [[ $x != hello ]] then err_exit "subshell in command substitution with 1 closed fails" fi -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! read line 2> /dev/null print done ! -if [[ $($SHELL /tmp/ksh$$ <&-) != done ]] +if [[ $($SHELL $tmp/script <&-) != done ]] then err_exit "executing script with 0 closed fails" fi trap '' INT -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! trap 'print bad' INT kill -s INT $$ print good ! -chmod +x /tmp/ksh$$ -if [[ $($SHELL /tmp/ksh$$) != good ]] +chmod +x $tmp/script +if [[ $($SHELL $tmp/script) != good ]] then err_exit "traps ignored by parent not ignored" fi trap - INT -cat > /tmp/ksh$$ <<- \! +cat > $tmp/script <<- \! read line /bin/cat ! -if [[ $($SHELL /tmp/ksh$$ <<! +if [[ $($SHELL $tmp/script <<! one two ! @@ -305,7 +303,7 @@ wait # not running --pipefail which would interfere with subsequent tests sleep 20 & pids=$! if [[ $(jobs -p) != $! ]] -then err_exit 'jobs -p not reporting a background job' +then err_exit 'jobs -p not reporting a background job' fi sleep 20 & pids="$pids $!" @@ -323,32 +321,31 @@ kill $pids command exec 3<> /dev/null if cat /dev/fd/3 >/dev/null 2>&1 then [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' - [[ $($SHELL -c 'print $(cat <(print foo) )' 2> /dev/null) == foo ]] || err_exit 'process substitution in subshell not working' - [[ $($SHELL -c $'tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null <<- \!!! + [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! line0 line1 line2 !!! wait - cat /tmp/ksh'$$x 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' - > /tmp/ksh$$x + cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' + > $tmp/scriptx [[ $($SHELL -c $' for i in 1 - do tee >(grep \'1$\' > /tmp/ksh'$$'x) > /dev/null <<- \!!! + do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! line0 line1 line2 !!! done wait - cat /tmp/ksh'$$x 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' + cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || err_exit 'process substitution of compound commands not working' fi [[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' -print cat > /tmp/ksh$$x -chmod +x /tmp/ksh$$x -[[ $($SHELL -c "print foo | /tmp/ksh$$x ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' +print cat > $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' [[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' [[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' exec 3<&- @@ -357,19 +354,18 @@ then [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not $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" fi exec 3> /dev/null -print 'print foo "$@"' > /tmp/ksh$$x -[[ $( print "(/tmp/ksh$$x bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' -print "#! $SHELL" > /tmp/ksh$$x -print 'print -- $0' >> /tmp/ksh$$x -chmod +x /tmp/ksh$$x -[[ $(/tmp/ksh$$x) == /tmp/ksh$$x ]] || err_exit "\$0 is $0 instead of /tmp/ksh$$x" -cat > /tmp/ksh$$x <<- \EOF +print 'print foo "$@"' > $tmp/scriptx +[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' +print "#! $SHELL" > $tmp/scriptx +print 'print -- $0' >> $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" +cat > $tmp/scriptx <<- \EOF myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} set -o pipefail sleep 3 | myfilter EOF -(( $($SHELL /tmp/ksh$$x) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' -rm -f /tmp/ksh$$x +(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' exec 3<&- ( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' $SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' @@ -406,13 +402,8 @@ $SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' EOF unset foo -function foo -{ - print bar -} -[[ ${foo} == bar ]] || err_exit '${foo} is not command substitution when foo unset' -[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' -[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' +[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' +[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' [[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' [[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' unset foo @@ -421,10 +412,57 @@ expected=foreback got=$(print -n fore;(sleep 2;print back)&) [[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" -for false in false $(whence -p false) +binfalse=$(whence -p false) +for false in false $binfalse do x=$($false) && err_exit "x=\$($false) should fail" $($false) && err_exit "\$($false) should fail" $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" done -[[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' +if env x-a=y >/dev/null 2>&1 +then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' +fi +float s=SECONDS +sleep=$(whence -p sleep) +for i in 1 2 +do print $i +done | while read sec; do ( $sleep $sec; $sleep $sec) done +(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' +s=SECONDS +set -o pipefail +for ((i=0; i < 30; i++)) +do print hello + sleep .1 +done | $sleep 1 +(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' +[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' +var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) +[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' + +exp= +got=$( + function fun + { + $binfalse && echo FAILED + } + : works if this line deleted : | + fun + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" +got=$( + : works if this line deleted : | + { $binfalse && echo FAILED; } + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" + +got=$( + : works if this line deleted : | + ( $binfalse && echo FAILED ) + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" + +( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/bracket.sh b/usr/src/lib/libshell/common/tests/bracket.sh index 0b36806fbf..496fdae5a4 100644 --- a/usr/src/lib/libshell/common/tests/bracket.sh +++ b/usr/src/lib/libshell/common/tests/bracket.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,17 +27,19 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + null='' if [[ ! -z $null ]] then err_exit "-z: null string should be of zero length" fi -file=/tmp/regresso$$ -newer_file=/tmp/regressn$$ +file=$tmp/original +newer_file=$tmp/newer if [[ -z $file ]] then err_exit "-z: $file string should not be of zero length" fi -trap "rm -f $file $newer_file" EXIT -rm -f $file if [[ -a $file ]] then err_exit "-a: $file shouldn't exist" fi @@ -119,11 +121,11 @@ fi if [[ $file -nt $newer_file ]] then err_exit "$newer_file should be newer than $file" fi -if [[ $file != /tmp/* ]] -then err_exit "$file should match /tmp/*" +if [[ $file != $tmp/* ]] +then err_exit "$file should match $tmp/*" fi -if [[ $file = '/tmp/*' ]] -then err_exit "$file should not equal /tmp/*" +if [[ $file = $tmp'/*' ]] +then err_exit "$file should not equal $tmp'/*'" fi [[ ! ( ! -z $null && ! -z x) ]] || err_exit "negation and grouping" [[ -z '' || -z '' || -z '' ]] || err_exit "three ors not working" @@ -211,17 +213,17 @@ done [[ aaaa == {2,5}(a) ]] || err_exit 'aaaa != {2,4}(a)' [[ abcdcdabcd == {3,6}(ab|cd) ]] || err_exit 'abcdcdabcd == {3,4}(ab|cd)' [[ abcdcdabcde == {5}(ab|cd)e ]] || err_exit 'abcdcdabcd == {5}(ab|cd)e' -) || err_exit 'Errors with {..}(...) patterns' +) || err_exit 'errors with {..}(...) patterns' [[ D290.2003.02.16.temp == D290.+(2003.02.16).temp* ]] || err_exit 'pattern match bug with +(...)' rm -rf $file { -[[ -N $file ]] && err_exit 'test -N /tmp/*: st_mtime>st_atime after creat' +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat' sleep 2 print 'hello world' -[[ -N $file ]] || err_exit 'test -N /tmp/*: st_mtime<=st_atime after write' +[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write' sleep 2 read -[[ -N $file ]] && err_exit 'test -N /tmp/*: st_mtime>st_atime after read' +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read' } > $file < $file if rm -rf "$file" && ln -s / "$file" then [[ -L "$file" ]] || err_exit '-L not working' @@ -242,4 +244,80 @@ i=hell test '(' = ')' && err_exit '"test ( = )" should not be true' [[ $($SHELL -c 'case F in ~(Eilr)[a-z0-9#]) print ok;;esac' 2> /dev/null) == ok ]] || err_exit '~(Eilr) not working in case command' [[ $($SHELL -c "case Q in ~(Fi)q | \$'\E') print ok;;esac" 2> /dev/null) == ok ]] || err_exit '~(Fi)q | \E not working in case command' + +for l in C en_US.ISO8859-15 +do [[ $($SHELL -c "LC_COLLATE=$l" 2>&1) ]] && continue + export LC_COLLATE=$l + set -- \ + 'A' 0 1 1 0 1 1 1 0 0 1 0 0 \ + 'Z' 0 1 1 0 1 1 1 0 0 1 0 0 \ + '/' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '.' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '_' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '-' 1 1 1 1 1 1 0 0 0 0 0 0 \ + '%' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '@' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '!' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '^' 0 0 0 0 0 0 1 1 1 1 1 1 \ + # retain this line # + while (( $# >= 13 )) + do c=$1 + shift + for p in \ + '[![.-.]]' \ + '[![.-.][:upper:]]' \ + '[![.-.]A-Z]' \ + '[!-]' \ + '[!-[:upper:]]' \ + '[!-A-Z]' \ + '[[.-.]]' \ + '[[.-.][:upper:]]' \ + '[[.-.]A-Z]' \ + '[-]' \ + '[-[:upper:]]' \ + '[-A-Z]' \ + # retain this line # + do e=$1 + shift + [[ $c == $p ]] + g=$? + [[ $g == $e ]] || err_exit "[[ '$c' == $p ]] for LC_COLLATE=$l failed -- expected $e, got $g" + done + done +done +integer n +if ( : < /dev/tty ) 2>/dev/null && exec {n}< /dev/tty +then [[ -t $n ]] || err_exit "[[ -t n ]] fails when n > 9" +fi +foo=([1]=a [2]=b [3]=c) +[[ -v foo[1] ]] || err_exit 'foo[1] should be set' +[[ ${foo[1]+x} ]] || err_exit '${foo[1]+x} should be x' +[[ ${foo[@]+x} ]] || err_exit '${foo[@]+x} should be x' +unset foo[1] +[[ -v foo[1] ]] && err_exit 'foo[1] should not be set' +[[ ${foo[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +bar=(a b c) +[[ -v bar[1] ]] || err_exit 'bar[1] should be set' +[[ ${bar[1]+x} ]] || err_exit '${foo[1]+x} should be x' +unset bar[1] +[[ ${bar[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +[[ -v bar ]] || err_exit 'bar should be set' +[[ -v bar[1] ]] && err_exit 'bar[1] should not be set' +integer z=( 1 2 4) +[[ -v z[1] ]] || err_exit 'z[1] should be set' +unset z[1] +[[ -v z[1] ]] && err_exit 'z[1] should not be set' +typeset -si y=( 1 2 4) +[[ -v y[6] ]] && err_exit 'y[6] should not be set' +[[ -v y[1] ]] || err_exit 'y[1] should be set' +unset y[1] +[[ -v y[1] ]] && err_exit 'y[1] should not be set' +x=abc +[[ -v x[0] ]] || err_exit 'x[0] should be set' +[[ ${x[0]+x} ]] || err_exit print '${x[0]+x} should be x' +[[ -v x[3] ]] && err_exit 'x[3] should not be set' +[[ ${x[3]+x} ]] && err_exit '${x[0]+x} should be Empty' +unset x +[[ ${x[@]+x} ]] && err_exit '${x[@]+x} should be Empty' +unset x y z foo bar exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/builtins.sh b/usr/src/lib/libshell/common/tests/builtins.sh index 08dac83a4e..cbd78fa98b 100644 --- a/usr/src/lib/libshell/common/tests/builtins.sh +++ b/usr/src/lib/libshell/common/tests/builtins.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,9 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test shell builtin commands Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test shell builtin commands builtin getconf : ${foo=bar} || err_exit ": failed" [[ $foo = bar ]] || err_exit ": side effects failed" @@ -171,30 +175,31 @@ if [[ $(command -v if) != if ]] then err_exit 'command -v not working' fi read -r var <<\! - + ! if [[ $var != "" ]] then err_exit "read -r of blank line not working" fi -mkdir -p /tmp/ksh$$/a/b/c 2>/dev/null || err_exit "mkdir -p failed" -$SHELL -c "cd /tmp/ksh$$/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" -trap 'print HUP' HUP -if [[ $(trap) != "trap -- 'print HUP' HUP" ]] -then err_exit '$(trap) not working' -fi -if [[ $(trap -p HUP) != 'print HUP' ]] -then err_exit '$(trap -p HUP) not working' -fi +mkdir -p $tmp/a/b/c 2>/dev/null || err_exit "mkdir -p failed" +$SHELL -c "cd $tmp/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" + +trap 'print TERM' TERM +exp=$'trap -- \'print TERM\' TERM\ntrap -- \'cd /; rm -rf '$tmp$'\' EXIT' +got=$(trap) +[[ $got == $exp ]] || err_exit "\$(trap) failed -- expected \"$exp\", got \"$got\"" +exp='print TERM' +got=$(trap -p TERM) +[[ $got == $exp ]] || err_exit "\$(trap -p TERM) failed -- expected \"$exp\", got \"$got\"" + [[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' [[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' [[ $($SHELL -c '( trap "" TERM);kill $$;print bad' == bad) ]] 2> /dev/null && err_exit 'trap ignored in subshell causes it to be ignored by parent' ${SHELL} -c 'kill -1 -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' ${SHELL} -c 'kill -1 -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' ${SHELL} -c 'kill -s HUP -$$' 2> /dev/null -[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' n=123 typeset -A base base[o]=8# @@ -266,23 +271,23 @@ OPTIND=1 if [[ $(getopts $'[+?X\ffoobar\fX]' v --man 2>&1) != *'Xhello world'X* ]] then err_exit '\f...\f not working in getopts usage strings' fi -if [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] +if [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] then err_exit 'printf %H not working' fi -if [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] +if [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] then err_exit 'printf %R not working' fi if [[ $(printf '%..:c\n' abc) != a:b:c ]] -then err_exit "printf '%..:c' not working" +then err_exit "printf '%..:c' not working" fi if [[ $(printf '%..*c\n' : abc) != a:b:c ]] -then err_exit "printf '%..*c' not working" +then err_exit "printf '%..*c' not working" fi if [[ $(printf '%..:s\n' abc def ) != abc:def ]] -then err_exit "printf '%..:s' not working" +then err_exit "printf '%..:s' not working" fi if [[ $(printf '%..*s\n' : abc def) != abc:def ]] -then err_exit "printf '%..*s' not working" +then err_exit "printf '%..*s' not working" fi [[ $(printf '%q\n') == '' ]] || err_exit 'printf "%q" with missing arguments' # we won't get hit by the one second boundary twice, right? @@ -296,12 +301,18 @@ behead() } print $'line1\nline2' | behead if [[ $left != line2 ]] -then err_exit "read reading ahead on a pipe" +then err_exit "read reading ahead on a pipe" fi -print -n $'{ read -r line;print $line;}\nhello' > /tmp/ksh$$ -chmod 755 /tmp/ksh$$ -trap 'rm -rf /tmp/ksh$$' EXIT -if [[ $($SHELL < /tmp/ksh$$) != hello ]] +read -n1 y <<! +abc +! +exp=a +if [[ $y != $exp ]] +then err_exit "read -n1 failed -- expected '$exp', got '$y'" +fi +print -n $'{ read -r line;print $line;}\nhello' > $tmp/script +chmod 755 $tmp/script +if [[ $($SHELL < $tmp/script) != hello ]] then err_exit 'read of incomplete line not working correctly' fi set -f @@ -321,19 +332,13 @@ wait $pid1 (( $? == 1 )) || err_exit "wait not saving exit value" wait $pid2 (( $? == 127 )) || err_exit "subshell job known to parent" -set --noglob -ifs=$IFS -IFS=, -set -- $(getconf LIBPATH) -IFS=$ifs env= -for v -do IFS=: - set -- $v - IFS=$ifs - eval [[ \$$2 ]] && env="$env $2=\"\$$2\"" +v=$(getconf LIBPATH) +for v in ${v//,/ } +do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && env="$env $v=\"\$$v\"" done -set --glob if [[ $(foo=bar; eval foo=\$foo $env exec -c \$SHELL -c \'print \$foo\') != bar ]] then err_exit '"name=value exec -c ..." not working' fi @@ -364,7 +369,7 @@ do arg=$1 val=$2 code=$3 err=$(printf "$fmt" "$arg" 2>&1 >/dev/null) printf "$fmt" "$arg" >/dev/null 2>&1 ret=$? - [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected $val, got $out" + [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'" if (( $code )) then [[ $err ]] || err_exit "printf $fmt $arg failed, error message expected" else [[ $err ]] && err_exit "$err: printf $fmt $arg failed, error message not expected -- got '$err'" @@ -398,6 +403,50 @@ do case $opt in *) err_exit "getopts $options failed -- got flag $opt" ;; esac done + +unset a +{ read -N3 a; read -N1 b;} <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -N3 here-document failed -- expected '$exp', got '$a'" +exp=d +[[ $b == $exp ]] || err_exit "read -N1 here-document failed -- expected '$exp', got '$b'" +read -n3 a <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -n3 here-document failed -- expected '$exp', got '$a'" +#(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} +#[[ $a == $exp ]] || err_exit "read -N3 from pipe failed -- expected '$exp', got '$a'" +#exp=d +#[[ $b == $exp ]] || err_exit "read -N1 from pipe failed -- expected '$exp', got '$b'" +#(print -n a;sleep 1; print -n bcde) | read -n3 a +#exp=a +#[[ $a == $exp ]] || err_exit "read -n3 from pipe failed -- expected '$exp', got '$a'" +#rm -f $tmp/fifo +#if mkfifo $tmp/fifo 2> /dev/null +#then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' +# read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' +# } 5< $tmp/fifo +# exp=a +# [[ $a == $exp ]] || err_exit "read -n3 from fifo failed -- expected '$exp', got '$a'" +# rm -f $tmp/fifo +# mkfifo $tmp/fifo 2> /dev/null +# (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' +# read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' +# } 5< $tmp/fifo +# exp=abc +# [[ $a == $exp ]] || err_exit "read -N3 from fifo failed -- expected '$exp', got '$a'" +# exp=d +# [[ $b == $exp ]] || err_exit "read -N1 from fifo failed -- expected '$exp', got '$b'" +#fi +#rm -f $tmp/fifo + function longline { integer i @@ -437,33 +486,43 @@ getconf UNIVERSE - ucb [[ $($SHELL -c 'echo -3') == -3 ]] || err_exit "echo -3 not working in ucb universe" typeset -F3 start_x=SECONDS total_t delay=0.02 typeset reps=50 leeway=5 -sleep $(( 2 * leeway * reps * delay )) | -for (( i=0 ; i < reps ; i++ )) -do read -N1 -t $delay -done -(( total_t = SECONDS - start_x )) -if (( total_t > leeway * reps * delay )) -then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" -elif (( total_t < reps * delay )) -then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" -fi -$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" -$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' +#sleep $(( 2 * leeway * reps * delay )) | +#for (( i=0 ; i < reps ; i++ )) +#do read -N1 -t $delay +#done +#(( total_t = SECONDS - start_x )) +#if (( total_t > leeway * reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" +#elif (( total_t < reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" +#fi +#$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" +#$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' [[ $(ulimit) == "$(ulimit -fS)" ]] || err_exit 'ulimit is not the same as ulimit -fS' -tmpfile=${TMP-/tmp}/ksh$$.2 -trap 'rm -f /tmp/ksh$$ "$tmpfile"' EXIT +tmpfile=$tmp/file.2 print $'\nprint -r -- "${.sh.file} ${LINENO} ${.sh.lineno}"' > $tmpfile [[ $( . "$tmpfile") == "$tmpfile 2 1" ]] || err_exit 'dot command not working' print -r -- "'xxx" > $tmpfile [[ $($SHELL -c ". $tmpfile"$'\n print ok' 2> /dev/null) == ok ]] || err_exit 'syntax error in dot command affects next command' -float sec=$SECONDS del=4 -exec 3>&2 2>/dev/null -$SHELL -c "( sleep 1; kill -ALRM \$\$ ) & sleep $del" 2> /dev/null -exitval=$? -(( sec = SECONDS - sec )) -exec 2>&3- -(( exitval )) && err_exit "sleep doesn't exit 0 with ALRM interupt" -(( sec > (del - 1) )) || err_exit "ALRM signal causes sleep to terminate prematurely -- expected 3 sec, got $sec" +#float sec=$SECONDS del=4 +#exec 3>&2 2>/dev/null +#$SHELL -c "( sleep 1; kill -ALRM \$\$ ) & sleep $del" 2> /dev/null +#exitval=$? +#(( sec = SECONDS - sec )) +#exec 2>&3- +#(( exitval )) && err_exit "sleep doesn't exit 0 with ALRM interupt" +#(( sec > (del - 1) )) || err_exit "ALRM signal causes sleep to terminate prematurely -- expected 3 sec, got $sec" +typeset -r z=3 +y=5 +for i in 123 z %x a.b.c +do ( unset $i) 2>/dev/null && err_exit "unset $i should fail" +done +a=() +for i in y y y[8] t[abc] y.d a.b a +do unset $i || print -u2 "err_exit unset $i should not fail" +done +[[ $($SHELL -c 'y=3; unset 123 y;print $?$y') == 1 ]] 2> /dev/null || err_exit 'y is not getting unset with unset 123 y' +[[ $($SHELL -c 'trap foo TERM; (trap;(trap) )') == 'trap -- foo TERM' ]] || err_exit 'traps not getting reset when subshell is last process' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/case.sh b/usr/src/lib/libshell/common/tests/case.sh index cca84686bd..1f04cfd30d 100644 --- a/usr/src/lib/libshell/common/tests/case.sh +++ b/usr/src/lib/libshell/common/tests/case.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/comvar.sh b/usr/src/lib/libshell/common/tests/comvar.sh index dfc9d9acfd..00eac1d188 100644 --- a/usr/src/lib/libshell/common/tests/comvar.sh +++ b/usr/src/lib/libshell/common/tests/comvar.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -85,7 +85,7 @@ foo=(integer x=3) if [[ ${foo} != *x=3* ]] then err_exit "compound variable with integer subvariable not working" fi -$SHELL -c $'x=(foo=bar)\n[[ x == x ]]' 2> /dev/null || +$SHELL -c $'x=(foo=bar)\n[[ x == x ]]' 2> /dev/null || err_exit '[[ ... ]] not working after compound assignment' unset foo [[ ${!foo.@} ]] && err_exit 'unset compound variable leaves subvariables' @@ -194,7 +194,7 @@ localvar [[ $($SHELL -c 'foo=();foo.[x]=(y z); print ${foo.x[@]}') == 'y z' ]] 2> /dev/null || err_exit 'foo=( [x]=(y z) not working' function staticvar { - if [[ $1 ]] + if [[ $1 ]] then print -r -- "$point" return fi @@ -291,7 +291,7 @@ foo=( ) eval foo2="$foo" foo2.hello=notok foo2.yes.yex=no foo2.extra=yes. -typeset -C bar bam +typeset -C bar bam { read -Cu3 bar read -Cu3 bam @@ -422,5 +422,120 @@ data.samples+=( command2="grrrr2" ) -[[ $data == %(()) ]] || err_exit "unbalanced parenthesis with compound variable containing array of compound variables" +[[ $data == %(()) ]] || err_exit "unbalanced parenthesis with compound variable containing array of compound variables" +typeset -C -A hello=( [foo]=bar) +[[ $(typeset -p hello) == 'typeset -C -A hello=([foo]=bar)' ]] || err_exit 'typeset -A -C with intial assignment not working' +# this caused a core dump before ksh93t+ +[[ $($SHELL -c 'foo=(x=3 y=4);function bar { typeset z=4;: $z;};bar;print ${!foo.@}') == 'foo.x foo.y' ]] 2> /dev/null || err_exit '${!foo.@} after function not working' + +function foo +{ + typeset tmp + read -C tmp + read -C tmp +} +foo 2> /dev/null <<- \EOF || err_exit 'deleting compound variable in function failed' + ( + typeset -A myarray3=( + [a]=( foo=bar) + [b]=( foo=bar) + [c d]=( foo=bar) + [e]=( foo=bar) + [f]=( foo=bar) + [g]=( foo=bar) + [h]=( foo=bar) + [i]=( foo=bar) + [j]=( foo=bar) + ) + ) + hello +EOF + +typeset -C -a mica01 +mica01[4]=( a_string="foo bar" ) +typeset -C more_content=( + some_stuff="hello" +) +mica01[4]+=more_content +expected=$'typeset -C -a mica01=([4]=(a_string=\'foo bar\';some_stuff=hello;))' +[[ $(typeset -p mica01) == "$expected" ]] || err_exit 'appened to indexed array compound variable not working' + +unset x +compound x=( integer x ; ) +[[ ! -v x.x ]] && err_exit 'x.x should be set' +expected=$'(\n\ttypeset -l -i x=0\n)' +[[ $(print -v x) == "$expected" ]] || err_exit "'print -v x' should be $expected" + +typeset -C -A hello19=( + [19]=( + one="xone 19" + two="xtwo 19" + ) + [23]=( + one="xone 23" + two="xtwo 23" + ) +) +expected="typeset -C -A hello19=([19]=(one='xone 19';two='xtwo 19';) [23]=(one='xone 23';two='xtwo 23';))" +[[ $(typeset -p hello19) == "$expected" ]] || print -u2 'typeset -p hello19 incorrect' +expected=$'(\n\tone=\'xone 19\'\n\ttwo=\'xtwo 19\'\n) (\n\tone=\'xone 23\'\n\ttwo=\'xtwo 23\'\n)' +[[ ${hello19[@]} == "$expected" ]] || print -u2 '${hello19[@]} incorrect' + +typeset -C -A foo1=( abc="alphabet" ) foo2=( abc="alphabet" ) +function add_one +{ + nameref left_op=$1 + typeset -C info + info.hello="world" + nameref x=info + left_op+=x +} +nameref node1="foo1[1234]" +add_one "node1" +add_one "foo2[1234]" +[[ "${foo1[1234]}" == "${foo2[1234]}" ]] || err_exit "test failed\n$(diff -u <( print -r -- "${foo1[1234]}") <(print -r -- "${foo2[1234]}"))." + +typeset -C tree +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + + # move local note into the array + typeset -m tr.subtree["a_node"]=node +} +f1 tree +expected=$'(\n\ttypeset -A subtree=(\n\t\t[a_node]=(\n\t\t\tone=hello\n\t\t\ttwo=world\n\t\t)\n\t)\n)' +[[ $tree == "$expected" ]] || err_exit 'move of compound local variable to global variable not working' + +typeset -C -A array +float array[12].amount=2.9 +expected='typeset -C -A array=([12]=(typeset -l -E amount=2.9;))' +[[ $(typeset -p array) == "$expected" ]] || err_exit 'typeset with compound variable with compound variable array not working' + +typeset -T foo_t=( + function diff + { + print 1.0 + return 0 + } +) +foo_t sw +compound output=( + integer one=1 + float mydiff=sw.diff + float end=.314 +) +[[ $output == *end=* ]] || err_exit "The field 'name' end is missing" + +compound cpv1=( integer f=2 ) +compound x=( + integer a=1 + compound b=cpv1 +) +[[ $x == *f=2* ]] || err_exit "The field b containg 'f=2' is missing" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/coprocess.sh b/usr/src/lib/libshell/common/tests/coprocess.sh index feff0bace2..dde9a49805 100644 --- a/usr/src/lib/libshell/common/tests/coprocess.sh +++ b/usr/src/lib/libshell/common/tests/coprocess.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -29,6 +29,9 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + if [[ -d /cygdrive ]] then err_exit cygwin detected - coprocess tests disabled - enable at the risk of wedging your system exit $((Errors)) @@ -46,11 +49,11 @@ function ping # id cat |& print -p "hello" read -p line -[[ $line == hello ]] || err_exit 'coprocessing fails' +[[ $line == hello ]] || err_exit 'coprocessing fails' exec 5>&p 6<&p print -u5 'hello again' || err_exit 'write on u5 fails' read -u6 line -[[ $line == 'hello again' ]] || err_exit 'coprocess after moving fds fails' +[[ $line == 'hello again' ]] || err_exit 'coprocess after moving fds fails' exec 5<&- 6<&- wait $! @@ -87,8 +90,7 @@ do (( count-- )) done kill $(jobs -p) 2>/dev/null -file=/tmp/regress$$ -trap "rm -f $file" EXIT +file=$tmp/regress cat > $file <<\! /bin/cat |& ! @@ -100,15 +102,24 @@ exec 5<&- 6>&- kill $(jobs -p) 2>/dev/null ${SHELL-ksh} |& -print -p $'print hello | cat\nprint Done' +cop=$! +exp=Done +print -p $'print hello | cat\nprint '$exp read -t 5 -p read -t 5 -p -if [[ $REPLY != Done ]] -then err_exit "${SHELL-ksh} coprocess not working" +got=$REPLY +if [[ $got != $exp ]] +then err_exit "${SHELL-ksh} coprocess io failed -- got '$got', expected '$exp'" fi exec 5<&p 6>&p exec 5<&- 6>&- -wait $! +{ sleep 4; kill $cop; } 2>/dev/null & +spy=$! +if wait $cop 2>/dev/null +then kill $spy 2>/dev/null +else err_exit "coprocess hung after 'exec 5<&p 6>&p; exec 5<&- 6>&-'" +fi +wait { echo line1 | grep 'line2' @@ -123,7 +134,7 @@ then err_exit "read -p hanging (SECONDS=$SECONDS count=$count)" fi wait $! -( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) || +( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) || err_exit "coprocess cleanup not working correctly" { : |& } 2>/dev/null || err_exit "subshell coprocess lingers in parent" @@ -163,7 +174,7 @@ r= print -u6 ok exec 6>&- sleep 1 - kill $! 2> /dev/null + kill $! 2> /dev/null ) && err_exit 'coprocess with subshell would hang' for sig in IOT ABRT do if ( trap - $sig ) 2> /dev/null @@ -178,7 +189,7 @@ do if ( trap - $sig ) 2> /dev/null kill -$sig $$ kill $pid sleep 2 - kill $$ + kill $$ ) & read -p ++EOF++ @@ -206,7 +217,7 @@ trap - TERM trap 'sleep_pid=; kill $pid; err_exit "coprocess 2 hung"' TERM { sleep 5; kill $$; } & sleep_pid=$! -cat |& +cat |& pid=$! print foo >&p 2> /dev/null || err_exit 'first write of foo to coprocess failed' print foo >&p 2> /dev/null || err_exit 'second write of foo to coprocess failed' @@ -218,7 +229,7 @@ trap - TERM trap 'sleep_pid=; kill $pid; err_exit "coprocess 3 hung"' TERM { sleep 5; kill $$; } & sleep_pid=$! -cat |& +cat |& pid=$! print -p foo print -p bar @@ -231,4 +242,72 @@ wait $pid 2> /dev/null trap - TERM [[ $sleep_pid ]] && kill $sleep_pid +exp=ksh +got=$(print -r $'#00315 +COATTRIBUTES=\'label=make \' +# @(#)$Id: libcoshell (AT&T Research) 2008-04-28 $ +_COSHELL_msgfd=5 +{ { (eval \'function fun { trap \":\" 0; return 1; }; trap \"exit 0\" 0; fun; exit 1\') && PATH= print -u$_COSHELL_msgfd ksh; } || { times && echo bsh >&$_COSHELL_msgfd; } || { echo osh >&$_COSHELL_msgfd; }; } >/dev/null 2>&1' | $SHELL 5>&1) +[[ $got == $exp ]] || err_exit "coshell(3) identification sequence failed -- expected '$exp', got '$got'" + +function cop +{ + read + print ok +} + +exp=ok + +cop |& +pid=$! +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +cop |& +pid=$! +( +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess subshell query failed -- expected $exp, got '$got'" +) +kill $pid 2>/dev/null +wait + +exp='no coprocess' + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +( +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess subshell query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait +) + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/cubetype.sh b/usr/src/lib/libshell/common/tests/cubetype.sh index f3597d258d..4a718d4a38 100644 --- a/usr/src/lib/libshell/common/tests/cubetype.sh +++ b/usr/src/lib/libshell/common/tests/cubetype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -120,7 +120,7 @@ typeset -T Cube_t=( for ((i=0; i < n; i++)) do Box_t b=(name=box2) -[[ ${b.name} == box2 ]] || err_exit "\${b.name} incorrect -- expected box2, got '${b.name}'" +[[ ${b.name} == box2 ]] || err_exit "\${b.name} incorrect -- expected box2, got '${b.name}'" (( b.len == 5 )) || err_exit "b.len incorrect for box2 -- expected 5, got '$(( b.len ))'" (( b.count == 1 )) || err_exit "b.count incorrect -- expected 1, got '$(( b.count ))'" Cube_t c=(name=cube1) @@ -134,7 +134,7 @@ Cube_t c=(name=cube1) (( c.count == 2 )) || err_exit 'c.count != 2' (( c.count == b.count )) || err_exit 'c.count != b.count' c.count=0 -Cube_t d=c +Cube_t d=c [[ $d == "$c" ]] || err_exit '$d != $c' eval "Cube_t zzz=$c" [[ $zzz == "$c" ]] || err_exit '$zzz != $c' @@ -149,6 +149,7 @@ for ((i=0; i < n; i++)) do Cube_t cc cc[2]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +[[ ${cc[0].x} == 8 ]] || err_exit 'cc[0].x !=8' [[ ${cc[2].y} == 3 ]] || err_exit '${cc[2].y} != 3' (( cc[2].y == 3 )) || err_exit '(( cc[2].y != 3))' [[ ${cc[2].colors[table]} == white ]] || err_exit '${cc[2].colors[table]} != white' @@ -162,7 +163,7 @@ unset cc[2].x cc[2].y cc[2].z (( cc[2].len == cc.len )) || err_exit 'cc[2].len != cc.len' (( cc[2].count == 6 )) || err_exit 'cc[2].count != 6' unset cc[2].name cc[2].colors cc[2].items -[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' +[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' cc.count=0 unset cc Cube_t -A cc @@ -181,7 +182,7 @@ unset cc[two].x cc[two].y cc[two].z (( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' (( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' unset cc[two].name unset cc[two].colors cc[two].items -[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' +[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' cc[two].count=0 unset cc Cube_t cc=( diff --git a/usr/src/lib/libshell/common/tests/enum.sh b/usr/src/lib/libshell/common/tests/enum.sh index 35d2a27952..1929472bb5 100644 --- a/usr/src/lib/libshell/common/tests/enum.sh +++ b/usr/src/lib/libshell/common/tests/enum.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -43,8 +43,8 @@ x[2]=green [[ $x == orange ]] || err_exit '$x is no longer orange' Color_t -A y y[foo]=yellow -[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' -(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' +[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' +(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' unset y typeset -a [Color_t] z z[green]=xyz diff --git a/usr/src/lib/libshell/common/tests/exit.sh b/usr/src/lib/libshell/common/tests/exit.sh index 01c407bf18..a14b0dcbec 100644 --- a/usr/src/lib/libshell/common/tests/exit.sh +++ b/usr/src/lib/libshell/common/tests/exit.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function abspath { base=$(basename $SHELL) @@ -34,28 +40,20 @@ function abspath print $newdir/$base } #test for proper exit of shell -Command=${0##*/} -integer Errors=0 builtin getconf ABSHELL=$(abspath) -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } print exit 0 >.profile ${ABSHELL} <<! HOME=$PWD \ PATH=$PATH \ SHELL=$ABSSHELL \ $( - set --noglob - ifs=$IFS - IFS=, - set -- $(getconf LIBPATH) - IFS=$ifs - for v - do IFS=: - set -- $v - IFS=$ifs - eval [[ \$$2 ]] && eval print -n \" \"\$2=\"\$$2\" + v=$(getconf LIBPATH) + for v in ${v//,/ } + do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && eval print -n \" \"\$v=\"\$$v\" done ) \ exec -c -a -ksh ${ABSHELL} -c "exit 1" 1>/dev/null 2>&1 @@ -77,6 +75,6 @@ if [[ $($SHELL ./run.sh) != 123 ]] then err_exit 'subshell trap on exit overwrites parent trap' fi cd ~- || err_exit "cd back failed" -rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" $SHELL -c 'builtin -f cmd getconf; getconf --"?-version"; exit 0' >/dev/null 2>&1 || err_exit 'ksh plugin exit failed -- was ksh built with CCFLAGS+=$(CC.EXPORT.DYNAMIC)?' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/expand.sh b/usr/src/lib/libshell/common/tests/expand.sh index 5dd46bdd8f..c63e7eb3e2 100644 --- a/usr/src/lib/libshell/common/tests/expand.sh +++ b/usr/src/lib/libshell/common/tests/expand.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/functions.sh b/usr/src/lib/libshell/common/tests/functions.sh index 0eaa17c688..146b537743 100644 --- a/usr/src/lib/libshell/common/tests/functions.sh +++ b/usr/src/lib/libshell/common/tests/functions.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,12 +28,10 @@ alias err_exit='err_exit $LINENO' integer Errors=0 Command=${0##*/} -tmp=/tmp/kshtf$$ -function cleanup -{ - rm -rf $tmp -} -mkdir $tmp || err_exit "mkdir $tmp failed" +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT integer foo=33 bar=bye @@ -89,11 +87,11 @@ function foobar { (return 0) } -> $tmp/shtests$$.1 +> $tmp/test1 { foobar -if [ -r $tmp/shtests$$.1 ] -then rm -r $tmp/shtests$$.1 +if [ -r $tmp/test1 ] +then rm -r $tmp/test1 else err_exit 'return within subshell inside function error' fi } @@ -138,37 +136,36 @@ fun() /bin/echo hello if [[ $(fun) != hello ]] then err_exit one line functions not working fi -trap cleanup EXIT -cat > $tmp/script$$ <<-\! +cat > $tmp/script <<-\! print -r -- "$1" ! -chmod +x $tmp/script$$ +chmod +x $tmp/script function passargs { - $tmp/script$$ "$@" + $tmp/script "$@" } if [[ $(passargs one) != one ]] then err_exit 'passing args from functions to scripts not working' fi -cat > $tmp/script$$ <<-\! +cat > $tmp/script <<-\! trap 'exit 0' EXIT function foo { - /tmp > /dev/null 2>&1 + /tmp > /dev/null 2>&1 } foo ! -if ! $tmp/script$$ -then err_exit 'exit trap incorrectly triggered' +if ! $tmp/script +then err_exit 'exit trap incorrectly triggered' fi -if ! $SHELL -c $tmp/script$$ -then err_exit 'exit trap incorrectly triggered when invoked with -c' +if ! $SHELL -c $tmp/script +then err_exit 'exit trap incorrectly triggered when invoked with -c' fi -$SHELL -c "trap 'rm $tmp/script$$' EXIT" -if [[ -f $tmp/script$$ ]] -then err_exit 'exit trap not triggered when invoked with -c' +$SHELL -c "trap 'rm $tmp/script' EXIT" +if [[ -f $tmp/script ]] +then err_exit 'exit trap not triggered when invoked with -c' fi -cat > $tmp/script$$ <<- \EOF +cat > $tmp/script <<- \EOF foobar() { return @@ -177,8 +174,8 @@ cat > $tmp/script$$ <<- \EOF foobar print -r -- "$1" EOF -chmod +x $tmp/script$$ -if [[ $( $SHELL $tmp/script$$ arg1 arg2) != arg2 ]] +chmod +x $tmp/script +if [[ $( $SHELL $tmp/script arg1 arg2) != arg2 ]] then err_exit 'arguments not restored by posix functions' fi function foo @@ -212,18 +209,17 @@ x=1 if [[ $(foo) != 3 ]] then err_exit 'variable assignment list not using parent scope' fi -unset -f foo$$ -#trap "rm -f $tmp/foo$$" EXIT INT -cat > $tmp/foo$$ <<! -function foo$$ +unset -f foobar +cat > $tmp/foobar <<! +function foobar { print foo } ! -chmod +x $tmp/foo$$ +chmod +x $tmp/foobar FPATH=$tmp -autoload foo$$ -if [[ $(foo$$ 2>/dev/null) != foo ]] +autoload foobar +if [[ $(foobar 2>/dev/null) != foo ]] then err_exit 'autoload not working' fi unset -f foobar @@ -233,14 +229,14 @@ function foobar return 0 } ( foobar ) 2> /dev/null || err_exit "cannot unset readonly variable in function" -if $SHELL -n 2> /dev/null <<-! +if $SHELL -n 2> /dev/null <<-! abc() ! then err_exit 'abc() without a function body is not a syntax error' fi function winpath { - usage='q pathname ...' + usage='q pathname ...' typeset var format=s while getopts "$usage" var do case $var in @@ -296,7 +292,7 @@ then err_exit 'set -e not inherited for posix functions' fi trap - ERR -function myexport +function myexport { nameref var=$1 if (( $# > 1 )) @@ -309,7 +305,6 @@ function myexport typeset val val=$(export | grep "^$1=") print ${val#"$1="} - } export dgk=base val=$(myexport dgk fun) @@ -384,8 +379,26 @@ function closure return $r } closure 0 || err_exit -u2 'for loop function optimization bug2' -mkdir $tmp/ksh$$ || err_exit "mkdir $tmp/ksh$$ failed" -cd $tmp/ksh$$ || err_exit "cd $tmp/ksh$$ failed" +dir=$tmp/dir +mkdir $dir +cd $dir || { err_exit "cd $dir failed"; exit 1; } + +( + function a { + print a + } + function b { + print 1 + a + print 2 + } > /dev/null + typeset -ft a b + PS4=X + b +) > file 2>&1 +[[ $(<file) == *'Xprint 2'* ]] || err_exit 'function trace disabled by function call' +rm -f file + print 'false' > try chmod +x try cat > tst <<- EOF @@ -400,18 +413,19 @@ EOF if [[ $($SHELL < tst) == error ]] then err_exit 'ERR trap not cleared' fi -FPATH=$tmp/ksh$$ -print ': This does nothing' > $tmp/ksh$$/foobar -chmod +x $tmp/ksh$$/foobar -unset -f foobar -{ foobar;} 2> /dev/null -if [[ $? != 126 ]] -then err_exit 'function file without function definition processes wrong error' +FPATH=$dir +print ': This does nothing' > foobar +chmod +x foobar +unset -f foobar +{ foobar; } 2>/dev/null +got=$? +exp=126 +if [[ $got != $exp ]] +then err_exit "function file without function definition processes wrong error -- expected '$exp', got '$got'" fi -print 'set a b c' > dotscript +print 'set a b c' > dotscript [[ $(PATH=$PATH: $SHELL -c '. dotscript;print $#') == 3 ]] || err_exit 'positional parameters not preserved with . script without arguments' cd ~- || err_exit "cd back failed" -cd /; rm -r $tmp/ksh$$ || err_exit "rm -r $tmp/ksh$$ failed" function errcheck { trap 'print ERR; return 1' ERR @@ -439,7 +453,7 @@ a() b() { : ;} [[ $(a) == a ]] || err_exit '.sh.fun not set correctly in a function' print $'a(){\ndate\n}' | $SHELL 2> /dev/null || err_exit 'parser error in a(){;date;}' -cat > $tmp/data$$.1 << '++EOF' +cat > $tmp/data1 << '++EOF' 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -461,7 +475,7 @@ cat > $tmp/data$$.1 << '++EOF' 19 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 20 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ++EOF -cat > $tmp/script$$ << '++EOF' +cat > $tmp/script << '++EOF' # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -727,10 +741,10 @@ f() { cat <<\M ++EOF -cat $tmp/data$$.1 >> $tmp/script$$ -printf 'M\n}\n\nf\n\n' >> $tmp/script$$ -$SHELL -c $tmp/script$$ > $tmp/data$$.2 -cmp -s $tmp/data$$.[12] || err_exit 'error with long functions' +cat $tmp/data1 >> $tmp/script +printf 'M\n}\n\nf\n\n' >> $tmp/script +$SHELL -c $tmp/script > $tmp/data2 +cmp -s $tmp/data[12] || err_exit 'error with long functions' v=1 function f { @@ -776,7 +790,7 @@ x=$( integer count=0 function err_f { - if ((count++==3)) + if ((count++==3)) then print failed else false fi @@ -785,7 +799,6 @@ x=$( false ) [[ $x == failed ]] && err_exit 'ERR trap executed multiple times' -trap cleanup EXIT export environment typeset global function f @@ -819,17 +832,17 @@ function f } f local global environment literal positional $SHELL -c ' - print exit 0 > '$tmp'/script$$ - chmod +x '$tmp'/script$$ + print exit 0 > '$tmp'/script + chmod +x '$tmp'/script unset var var=( ident=1 ) function fun { - PATH='$tmp' script$$ + PATH='$tmp' script } fun ' || err_exit "compound variable cleanup before script exec failed" -( $SHELL << \++EOF++ +( $SHELL << \++EOF++ function main { typeset key @@ -921,10 +934,7 @@ unset -f .sh.fun.set # tests for debug functions basefile=${.sh.file} integer baseline -cleanup -trap 'rm $tmp' EXIT -tmp=${TMPDIR:-/tmp}/ksh$$.1 -cat > $tmp << \+++ +cat > $tmp/debug << \+++ : line 1 : line 3 @@ -943,7 +953,7 @@ function _Dbg_print_frame [[ $arg == DEBUG ]] && ((baseline++)) [[ $line == "$baseline" ]] || err_exit "line number for level 0 is $line not $baseline" elif ((pos==1)) - then [[ $filename == "$tmp" ]] || err_exit "filename for level 1 is $filename not $tmp" + then [[ $filename == "$tmp/debug" ]] || err_exit "filename for level 1 is $filename not $tmp/debug" [[ $* == 'foo bar' ]] || err_exit "args are '$*', not 'foo bar'" [[ $line == $arg ]] || err_exit "line number for level 1 is $line not $arg" else err_exit "level should be 0 or 1 but is $pos" @@ -963,9 +973,9 @@ function _Dbg_debug_trap_handler ((baseline=LINENO+2)) trap '_Dbg_debug_trap_handler' DEBUG -. $tmp foo bar +. $tmp/debug foo bar trap '' DEBUG - + caller() { integer .level=.sh.level .max=.sh.level-1 while((--.level>=0)) @@ -978,4 +988,84 @@ bar() { caller;} set -- $(bar) [[ $1 == $2 ]] && err_exit ".sh.inline optimization bug" ( $SHELL -c ' function foo { typeset x=$1;print $1;};z=();z=($(foo bar)) ') 2> /dev/null || err_exit 'using a function to set an array in a command sub fails' + +{ +got=$( +s=$(ulimit -s) +if [[ $s == +([[:digit:]]) ]] && (( s < 16384 )) +then ulimit -s 16384 2>/dev/null +fi +$SHELL << \+++ +f() +{ + if (($1>1)) + then x=$(f $(($1-1))) || exit 1 + fi + return 0 +} +f 257 && print ok ++++ +) +} 2>/dev/null +[[ $got == ok ]] || err_exit 'cannot handle comsub depth > 256 in function' + +tmp1=$tmp/job.1 +tmp2=$tmp/job.2 +cat > $tmp1 << +++ +#! $SHELL +print \$\$ ++++ +chmod +x $tmp1 +function foo +{ + typeset pid + $tmp1 > $tmp2 & pid=$! + wait $! + [[ $(< $tmp2) == $pid ]] || err_exit 'wrong pid for & job in function' +} +foo +# make sure compiled functions work +[[ $(tmp=$tmp $SHELL <<- \++++ + cat > $tmp/functions <<- \EOF + function bar + { + print foo + } + function foobar + { + bar + } + EOF + ${SHCOMP:-${SHELL%/*}/shcomp} $tmp/functions > $tmp/foobar + rm -f "$tmp/functions" + chmod +x $tmp/foobar + rm $tmp/!(dir|foobar) + FPATH=$tmp + PATH=$FPATH:$PATH + foobar +++++ +) == foo ]] > /dev/null || err_exit 'functions compiled with shcomp not working' +# test for functions in shell having side effects. +unset -f foo foobar bar +cd "$tmp" +FPATH=$PWD +PATH=$FPATH:$PATH +cat > foo <<- \EOF + function bar + { + print foobar + } + function foo + { + bar + } +EOF +chmod +x foo +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effect of function foo' +unset -f foo bar +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effects of function foo after reload' +[[ $(typeset +f) == *bar* ]] && err_exit 'function in subshell leaving side effects of function bar after reload' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/glob.sh b/usr/src/lib/libshell/common/tests/glob.sh index 2c3ccd09d3..fa22291c96 100644 --- a/usr/src/lib/libshell/common/tests/glob.sh +++ b/usr/src/lib/libshell/common/tests/glob.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,7 +24,11 @@ function err_exit } alias err_exit='err_exit $LINENO' -integer aware=0 contrary=0 ignorant=0 +Command=${0##*/} +integer aware=0 contrary=0 errors=0 ignorant=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT function test_glob { @@ -84,17 +88,11 @@ function test_case } alias test_case='test_case $LINENO' -Command=${0##*/} -tmp=/tmp/ksh$$ -integer errors=0 unset undefined export LC_COLLATE=C -mkdir $tmp || err_exit "mkdir $tmp failed" -trap "cd /; rm -rf $tmp" EXIT -cd $tmp || err_exit "cd $tmp failed" -rm -rf * +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } touch B b set -- * diff --git a/usr/src/lib/libshell/common/tests/grep.sh b/usr/src/lib/libshell/common/tests/grep.sh index 82c0e13cac..40a80a07a7 100644 --- a/usr/src/lib/libshell/common/tests/grep.sh +++ b/usr/src/lib/libshell/common/tests/grep.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,6 +28,9 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function grep { # @@ -84,8 +87,7 @@ function grep let tc # set the return value } -trap 'rm -f /tmp/grep$$' EXIT -cat > /tmp/grep$$ <<\! +cat > $tmp/grep <<\! this is a food bar test to see how many lines find both foo and bar. Some line contain foo only, @@ -96,7 +98,7 @@ There should be six lines with foo and bar. There are only two line with out foo but with bar. ! -if (( $(grep -c 'foo*bar' /tmp/grep$$ ) != 6)) +if (( $(grep -c 'foo*bar' $tmp/grep ) != 6)) then err_exit fi exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/heredoc.sh b/usr/src/lib/libshell/common/tests/heredoc.sh index aadc9cdeec..7b3c923bf0 100644 --- a/usr/src/lib/libshell/common/tests/heredoc.sh +++ b/usr/src/lib/libshell/common/tests/heredoc.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,9 +27,12 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -f=/tmp/here1$$ -g=/tmp/here2$$ -trap "rm -f $f $g" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +f=$tmp/here1 +g=$tmp/here2 cat > $f <<! hello world ! @@ -143,7 +146,7 @@ abc EOF) != $'#abc\nabc' ]] then err_exit 'comments not preserved in here-documents' fi -cat > "$f" <<- '!!!!' +cat > "$f" <<- '!!!!' builtin cat : << EOF $PWD @@ -173,7 +176,7 @@ chmod 755 "$f" if [[ $($SHELL "$f") != abc ]] then err_exit 'here document descritor was closed' fi -cat > "$f" <<- '!!!!' +cat > "$f" <<- '!!!!' exec 0<&- foobar() { @@ -207,9 +210,9 @@ if [[ $($SHELL "$f") != foobar ]] then err_exit 'here document with stdin closed failed' fi printf $'cat <<# \\!!!\n\thello\n\t\tworld\n!!!' > $f -[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for quoted here documents" +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for quoted here documents" printf $'w=world;cat <<# !!!\n\thello\n\t\t$w\n!!!' > $f -[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for non-quoted here documents" +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for non-quoted here documents" [[ $( $SHELL <<- \++++ S=( typeset a ) function S.a.get @@ -226,4 +229,27 @@ printf $'w=world;cat <<# !!!\n\thello\n\t\t$w\n!!!' > $f ${ g;} EOF ' 2> /dev/null) == ok ]] || err_exit '${ command;} not working in heredoc' +script=$f +{ +for ((i=0; i < 406; i++)) +do print ': 23456789012345678' +done +print : 123456789123 +cat <<- \EOF +eval "$( + { cat ; } <<MARKER + print hello + MARKER +)" +EOF +} > $script +chmod +x $script +[[ $($SHELL $script) == hello ]] 2> /dev/null || err_exit 'heredoc embeded in command substitution fails at buffer boundary' + +got=$( cat << EOF +\ +abc +EOF) +[[ $got == abc ]] || err_exit 'line continuation at start of buffer not working' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/io.sh b/usr/src/lib/libshell/common/tests/io.sh index a8b1b8a030..3468fe9429 100644 --- a/usr/src/lib/libshell/common/tests/io.sh +++ b/usr/src/lib/libshell/common/tests/io.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,29 +28,29 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + unset HISTFILE function fun { - while command exec 3>&1 - do break + while command exec 3>&1 + do break done 2> /dev/null print -u3 good } -print 'read -r a;print -r -u$1 -- "$a"' > /tmp/mycat$$ -chmod 755 /tmp/mycat$$ +print 'read -r a;print -r -u$1 -- "$a"' > $tmp/mycat +chmod 755 $tmp/mycat for ((i=3; i < 10; i++)) do - eval "a=\$(print foo | /tmp/mycat$$" $i $i'>&1 > /dev/null |cat)' 2> /dev/null + eval "a=\$(print foo | $tmp/mycat" $i $i'>&1 > /dev/null |cat)' 2> /dev/null [[ $a == foo ]] || err_exit "bad file descriptor $i in comsub script" done -rm -f /tmp/mycat$$ exec 3> /dev/null [[ $(fun) == good ]] || err_exit 'file 3 closed before subshell completes' exec 3>&- -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap 'rm -rf /tmp/ksh$$' EXIT -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || { err_exit "cd $tmp failed"; exit ; } print foo > file1 print bar >> file1 if [[ $(<file1) != $'foo\nbar' ]] @@ -59,19 +59,55 @@ fi set -o noclobber exec 3<> file1 read -u3 line -if [[ $line != foo ]] -then err_exit '<> not working right with read' +exp=foo +if [[ $line != $exp ]] +then err_exit "read on <> fd failed -- expected '$exp', got '$line'" fi if ( 4> file1 ) 2> /dev/null then err_exit 'noclobber not causing exclusive open' fi set +o noclobber -if command exec 4< /dev/fd/3 -then read -u4 line - if [[ $line != bar ]] - then '4< /dev/fd/3 not working correctly' - fi + +FDFS=( + ( dir=/proc/self/fd semantics='open' ) + ( dir=/proc/$$/fd semantics='open' ) + ( dir=/dev/fd semantics='open|dup' ) + ( dir=/dev/fd semantics='dup' ) +) +for ((fdfs=0; fdfs<${#FDFS[@]}-1; fdfs++)) +do [[ -e ${FDFS[fdfs].dir} ]] && { command : > ${FDFS[fdfs].dir}/1; } 2>/dev/null && break +done + +exec 3<> file1 +if command exec 4< ${FDFS[fdfs].dir}/3 +then read -u3 got + read -u4 got + exp='foo|bar' + case $got in + foo) semantics='open' ;; + bar) semantics='dup' ;; + *) semantics='failed' ;; + esac + [[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "'4< ${FDFS[fdfs].dir}/3' $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" fi + +# 2004-11-25 ancient /dev/fd/N redirection bug fix +got=$( + { + print -n 1 + print -n 2 > ${FDFS[fdfs].dir}/2 + print -n 3 + print -n 4 > ${FDFS[fdfs].dir}/2 + } 2>&1 +) +exp='1234|4' +case $got in +1234) semantics='dup' ;; +4) semantics='open' ;; +*) semantics='failed' ;; +esac +[[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "${FDFS[fdfs].dir}/N $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" + cat > close0 <<\! exec 0<&- echo $(./close1) @@ -91,15 +127,15 @@ cat > close0 <<\! ! ./close0 2> /dev/null || err_exit "multiple exec 4< /dev/null can fail" $SHELL -c ' - trap "rm -f in$$ out$$" EXIT + trap "rm -f in out" EXIT for ((i = 0; i < 1000; i++)) do print -r -- "This is a test" - done > in$$ - > out$$ - exec 1<> out$$ + done > in + > out + exec 1<> out builtin cat - print -r -- "$(cat in$$)" - cmp -s in$$ out$$' 2> /dev/null + print -r -- "$(<in)" + cmp -s in out' 2> /dev/null [[ $? == 0 ]] || err_exit 'builtin cat truncates files' cat >| script <<-\! print hello @@ -122,7 +158,7 @@ read line if [[ $line != foo ]] then err_exit 'file descriptor not restored after exec in subshell' fi -exec 3>&- 4>&-; cd /; rm -r /tmp/ksh$$ || err_exit "rm -r /tmp/ksh$$ failed" +exec 3>&- 4>&- [[ $( { read -r line;print -r -- "$line" ( @@ -137,37 +173,26 @@ line 2 line 3 !) == $'line 1\nline 2\nline 3' ]] || err_exit 'read error with subshells' # 2004-05-11 bug fix -cat > /tmp/io$$.1 <<- \++EOF++ - script=/tmp/io$$.2 - trap 'rm -f $script' EXIT - exec 9> $script +cat > $tmp/1 <<- ++EOF++ + script=$tmp/2 + trap "rm -f \$script" EXIT + exec 9> \$script for ((i=3; i<9; i++)) - do eval "while read -u$i; do : ;done $i</dev/null" - print -u9 "exec $i< /dev/null" + do eval "while read -u\$i; do : ;done \$i</dev/null" + print -u9 "exec \$i< /dev/null" done for ((i=0; i < 60; i++)) do print -u9 -f "%.80c\n" ' ' done print -u9 'print ok' exec 9<&- - chmod +x $script - $script + chmod +x \$script + \$script ++EOF++ -chmod +x /tmp/io$$.1 -[[ $($SHELL /tmp/io$$.1) == ok ]] || err_exit "parent i/o causes child script to fail" -rm -rf /tmp/io$$.[12] -# 2004-11-25 ancient /dev/fd/NN redirection bug fix -x=$( - { - print -n 1 - print -n 2 > /dev/fd/2 - print -n 3 - print -n 4 > /dev/fd/2 - } 2>&1 -) -[[ $x == "1234" ]] || err_exit "/dev/fd/NN redirection fails to dup" -# 2004-12-20 redirction loss bug fix -cat > /tmp/io$$.1 <<- \++EOF++ +chmod +x $tmp/1 +[[ $($SHELL $tmp/1) == ok ]] || err_exit "parent i/o causes child script to fail" +# 2004-12-20 redirection loss bug fix +cat > $tmp/1 <<- \++EOF++ function a { trap 'print ok' EXIT @@ -175,49 +200,47 @@ cat > /tmp/io$$.1 <<- \++EOF++ } a ++EOF++ -chmod +x /tmp/io$$.1 -[[ $(/tmp/io$$.1) == ok ]] || err_exit "trap on EXIT loses last command redirection" -print > /dev/null {n}> /tmp/io$$.1 -[[ ! -s /tmp/io$$.1 ]] && newio=1 -rm -rf /tmp/io$$.1 -if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] +chmod +x $tmp/1 +[[ $($tmp/1) == ok ]] || err_exit "trap on EXIT loses last command redirection" +print > /dev/null {n}> $tmp/1 +[[ ! -s $tmp/1 ]] && newio=1 +if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] then err_exit "{n}<&0 not working with for loop" fi [[ $({ read -r;read -u3 3<&0; print -- "$REPLY" ;} <<! hello world !) == world ]] || err_exit 'I/O not synchronized with <&' -trap 'rm -f /tmp/seek$$; exit $((Errors+1))' EXIT x="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNSPQRSTUVWXYZ1234567890" for ((i=0; i < 62; i++)) do printf "%.39c\n" ${x:i:1} -done > /tmp/seek$$ -if command exec 3<> /tmp/seek$$ +done > $tmp/seek +if command exec 3<> $tmp/seek then (( $(3<#) == 0 )) || err_exit "not at position 0" (( $(3<# ((EOF))) == 40*62 )) || err_exit "not at end-of-file" - command exec 3<# ((40*8)) || err_exit "absolute seek fails" + command exec 3<# ((40*8)) || err_exit "absolute seek fails" read -u3 - [[ $REPLY == +(i) ]] || err_exit "expecting iiii..." + [[ $REPLY == +(i) ]] || err_exit "expected iiii..., got $REPLY" [[ $(3<#) == $(3<# ((CUR)) ) ]] || err_exit '$(3<#)!=$(3<#((CUR)))' command exec 3<# ((CUR+80)) read -u3 - [[ $REPLY == {39}(l) ]] || err_exit "expecting lll..." + [[ $REPLY == {39}(l) ]] || err_exit "expected lll..., got $REPLY" command exec 3<# ((EOF-80)) read -u3 - [[ $REPLY == +(9) ]] || err_exit "expecting 999...; got $REPLY" + [[ $REPLY == +(9) ]] || err_exit "expected 999..., got $REPLY" command exec 3># ((80)) print -u3 -f "%.39c\n" @ command exec 3># ((80)) read -u3 - [[ $REPLY == +(@) ]] || err_exit "expecting @@@..." + [[ $REPLY == +(@) ]] || err_exit "expected @@@..., got $REPLY" read -u3 - [[ $REPLY == +(d) ]] || err_exit "expecting ddd..." + [[ $REPLY == +(d) ]] || err_exit "expected ddd..., got $REPLY" command exec 3># ((EOF)) print -u3 -f "%.39c\n" ^ (( $(3<# ((CUR-0))) == 40*63 )) || err_exit "not at extended end-of-file" - command exec 3<# ((40*62)) + command exec 3<# ((40*62)) read -u3 - [[ $REPLY == +(^) ]] || err_exit "expecting ddd..." + [[ $REPLY == +(^) ]] || err_exit "expected ddd..., got $REPLY" command exec 3<# ((0)) command exec 3<# *jjjj* read -u3 @@ -227,24 +250,22 @@ then (( $(3<#) == 0 )) || err_exit "not at position 0" [[ $REPLY == {39}(l) ]] || err_exit "<## pattern failed to position" command exec 3<# *abc* read -u3 && err_exit "not found pattern not positioning at eof" - cat /tmp/seek$$ | read -r <# *WWW* + cat $tmp/seek | read -r <# *WWW* [[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes' - { < /tmp/seek$$ <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' -else err_exit "/tmp/seek$$: cannot open for reading" + { < $tmp/seek <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' +else err_exit "$tmp/seek: cannot open for reading" fi command exec 3<&- || 'cannot close 3' for ((i=0; i < 62; i++)) do printf "%.39c\n" ${x:i:1} -done > /tmp/seek$$ -if command exec {n}<> /tmp/seek$$ +done > $tmp/seek +if command exec {n}<> $tmp/seek then { command exec {n}<#((EOF)) ;} 2> /dev/null || err_exit '{n}<# not working' if $SHELL -c '{n}</dev/null' 2> /dev/null then (( $({n}<#) == 40*62)) || err_exit '$({n}<#) not working' else err_exit 'not able to parse {n}</dev/null' fi fi -trap "" EXIT -rm -f /tmp/seek$$ $SHELL -ic ' { print -u2 || exit 2 @@ -258,9 +279,8 @@ $SHELL -ic ' } 3> /dev/null 4> /dev/null 5> /dev/null 6> /dev/null 7> /dev/null 8> /dev/null 9> /dev/null' > /dev/null 2>&1 exitval=$? (( exitval )) && err_exit "print to unit $exitval failed" -trap 'rm -rf /tmp/io.sh$$*' EXIT -$SHELL -c "{ > /tmp/io.sh$$.1 ; date;} >&- 2> /dev/null" > /tmp/io.sh$$.2 -[[ -s /tmp/io.sh$$.1 || -s /tmp/io.sh$$.2 ]] && err_exit 'commands with standard output closed produce output' +$SHELL -c "{ > $tmp/1 ; date;} >&- 2> /dev/null" > $tmp/2 +[[ -s $tmp/1 || -s $tmp/2 ]] && err_exit 'commands with standard output closed produce output' $SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard output not passed to subshell' [[ $(cat <<- \EOF | $SHELL do_it_all() @@ -273,12 +293,26 @@ $SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard out EOF) == 'hello world' ]] || err_exit 'invalid readahead on stdin' $SHELL -c 'exec 3>; /dev/null' 2> /dev/null && err_exit '>; with exec should be an error' $SHELL -c ': 3>; /dev/null' 2> /dev/null || err_exit '>; not working with at all' -print hello > /tmp/io.sh$$.1 -if ! $SHELL -c "false >; /tmp/io.sh$$.1" 2> /dev/null -then [[ $(</tmp/io.sh$$.1) == hello ]] || err_exit '>; not preserving file on failure' +print hello > $tmp/1 +if ! $SHELL -c "false >; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '>; not preserving file on failure' fi -if ! $SHELL -c "sed -e 's/hello/hello world/' /tmp/io.sh$$.1" >; /tmp/io.sh$$.1 2> /dev/null -then [[ $(</tmp/io.sh$$.1) == 'hello world' ]] || err_exit '>; not updating file on success' +if ! $SHELL -c "sed -e 's/hello/hello world/' $tmp/1" >; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == 'hello world' ]] || err_exit '>; not updating file on success' +fi + +$SHELL -c 'exec 3<>; /dev/null' 2> /dev/null && err_exit '<>; with exec should be an error' +$SHELL -c ': 3<>; /dev/null' 2> /dev/null || err_exit '<>; not working with at all' +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c "false <>; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == $'hello\nworld' ]] || err_exit '<>; not preserving file on failure' +fi +if ! $SHELL -c "head -1 $tmp/1" <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '<>; not truncating file on success of head' +fi +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c head < $tmp/1 <#((6)) <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == world ]] || err_exit '<>; not truncating file on success of behead' fi unset y @@ -303,25 +337,41 @@ abcdefg [[ $b == d ]] || err_exit 'read -N1 from pipe not working' (print -n a;sleep 1; print -n bcde) |read -n3 a [[ $a == a ]] || err_exit 'read -n3 from pipe not working' -rm -f /tmp/fifo$$ -if mkfifo /tmp/fifo$$ 2> /dev/null -then (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & +if mkfifo $tmp/fifo 2> /dev/null +then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & { read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' - } 5< /tmp/fifo$$ + } 5< $tmp/fifo [[ $a == a ]] || err_exit 'read -n3 from fifo not working' - rm -f /tmp/fifo$$ - mkfifo /tmp/fifo$$ 2> /dev/null - (print -n a; sleep 1;print -n bcde) > /tmp/fifo$$ & + rm -f $tmp/fifo + mkfifo $tmp/fifo 2> /dev/null + (print -n a; sleep 1;print -n bcde) > $tmp/fifo & { read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' - } 5< /tmp/fifo$$ + } 5< $tmp/fifo [[ $a == abc ]] || err_exit 'read -N3 from fifo not working' [[ $b == d ]] || err_exit 'read -N1 from fifo not working' fi -rm -f /tmp/fifo$$ +( + print -n 'prompt1: ' + sleep .1 + print line2 + sleep .1 + print -n 'prompt2: ' + sleep .1 +) | { + read -t2 -n 1000 line1 + read -t2 -n 1000 line2 + read -t2 -n 1000 line3 + read -t2 -n 1000 line4 +} +[[ $? == 0 ]] && err_exit 'should have time out' +[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '" +[[ $line2 == line2 ]] || err_exit "line2 should be line2" +[[ $line3 == 'prompt2: ' ]] || err_exit "line3 should be 'prompt2: '" +[[ ! $line4 ]] || err_exit "line4 should be empty" if $SHELL -c "export LC_ALL=en_US.UTF-8; c=$'\342\202\254'; [[ \${#c} == 1 ]]" 2>/dev/null then lc_utf8=en_US.UTF-8 @@ -370,4 +420,32 @@ then export LC_ALL=en_US.UTF-8 fi fi +exec 3<&2 +file=$tmp/file +redirect 5>$file 2>&5 +print -u5 -f 'This is a test\n' +print -u2 OK +exec 2<&3 +exp=$'This is a test\nOK' +got=$(< $file) +[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")" +print 'hello world' > $file +1<>; $file 1># ((5)) +(( $(wc -c < $file) == 5 )) || err_exit "$file was not truncate to 5 bytes" + +$SHELL -c "PS4=':2:' + exec 1> $tmp/21.out 2> $tmp/22.out + set -x + printf ':1:A:' + print \$(:) + print :1:Z:" 1> $tmp/11.out 2> $tmp/12.out +[[ -s $tmp/11.out ]] && err_exit "standard output leaked past redirection" +[[ -s $tmp/12.out ]] && err_exit "standard error leaked past redirection" +exp=$':1:A:\n:1:Z:' +got=$(<$tmp/21.out) +[[ $exp == "$got" ]] || err_exit "standard output garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" +exp=$':2:printf :1:A:\n:2::\n:2:print\n:2:print :1:Z:' +got=$(<$tmp/22.out) +[[ $exp == "$got" ]] || err_exit "standard error garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/locale.sh b/usr/src/lib/libshell/common/tests/locale.sh deleted file mode 100644 index ab94722e2d..0000000000 --- a/usr/src/lib/libshell/common/tests/locale.sh +++ /dev/null @@ -1,104 +0,0 @@ -######################################################################## -# # -# This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # -# and is licensed under the # -# Common Public License, Version 1.0 # -# by AT&T Intellectual Property # -# # -# A copy of the License is available at # -# http://www.opensource.org/licenses/cpl1.0.txt # -# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # -# # -# 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}" - let Errors+=1 -} -alias err_exit='err_exit $LINENO' - -Command=${0##*/} -integer Errors=0 - -# LC_ALL=debug is an ast specific debug/test locale - -if [[ "$(LC_ALL=debug $SHELL <<- \+EOF+ - x=a<1z>b<2yx>c - print ${#x} - +EOF+)" != 5 - ]] -then err_exit '${#x} not working with multibyte locales' -fi - -export LC_ALL=C -if (( $($SHELL -c $'export LC_ALL=en_US.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 )) -then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'Multibyte ${var:offset:len} not working correctly' -fi - -export LC_ALL=C -a=$($SHELL -c '/' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -b=$($SHELL -c '(LC_ALL=debug / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" -b=$($SHELL -c '(LC_ALL=debug; / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") -[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" - -# test shift-jis \x81\x40 ... \x81\x7E encodings -# (shift char followed by 7 bit ascii) - -typeset -i16 chr -for lc_all in $(PATH=/bin:/usr/bin locale -a 2>/dev/null | grep -i jis) -do export LC_ALL=$lc_all - for ((chr=0x40; chr<=0x7E; chr++)) - do c=${chr#16#} - for s in \\x81\\x$c \\x$c - do b="$(printf "$s")" - eval n=\$\'$s\' - [[ $b == "$n" ]] || err_exit "LC_ALL=$lc_all printf difference for \"$s\" -- expected '$n', got '$b'" - u=$(print -- $b) - q=$(print -- "$b") - [[ $u == "$q" ]] || err_exit "LC_ALL=$lc_all quoted print difference for \"$s\" -- $b => '$u' vs \"$b\" => '$q'" - done - done -done - -# test multibyte value/trace format -- $'\303\274' is UTF-8 u-umlaut - -LC_ALL=C -lc_all=de_DE.UTF-8 -c=$(LC_ALL=C $SHELL -c "printf $':%2s:\n' $'\303\274'") -u=$(LC_ALL=$lc_all $SHELL -c "printf $':%2s:\n' $'\303\274'" 2>/dev/null) -if [[ "$c" != "$u" ]] -then LC_ALL=$lc_all - x=$'+2+ typeset item.text\ -+3+ item.text=\303\274\ -+4+ print -- \303\274\ -\303\274\ -+5+ eval $\'arr[0]=(\\n\\ttext=\\303\\274\\n)\' -+2+ arr[0].text=ü\ -+6+ print -- \303\274\ -ü\ -+7+ eval txt=$\'(\\n\\ttext=\\303\\274\\n)\' -+2+ txt.text=\303\274\ -+8+ print -- \'(\' text=$\'\\303\\274\' \')\'\ -( text=\303\274 )' - u=$(LC_ALL=$lc_all PS4='+$LINENO+ ' $SHELL -x -c " - item=(typeset text) - item.text=$'\303\274' - print -- \"\${item.text}\" - eval \"arr[0]=\$item\" - print -- \"\${arr[0].text}\" - eval \"txt=\${arr[0]}\" - print -- \$txt - " 2>&1) - [[ "$u" == "$x" ]] || err_exit LC_ALL=$lc_all multibyte value/trace format failed -fi - -exit $Errors diff --git a/usr/src/lib/libshell/common/tests/nameref.sh b/usr/src/lib/libshell/common/tests/nameref.sh index 21a672db14..7bb9ec2c91 100644 --- a/usr/src/lib/libshell/common/tests/nameref.sh +++ b/usr/src/lib/libshell/common/tests/nameref.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function checkref { nameref foo=$1 bar=$2 @@ -80,7 +84,7 @@ nameref x=.foo.bar if [[ ${!x} != .foo.bar ]] then err_exit "${!x} not working" fi -typeset +n x $(typeset +n) +typeset +n x $(typeset +n) unset x nameref x=.foo.bar function x.set @@ -96,7 +100,7 @@ fi if [[ $(typeset -n) != x=.foo.bar ]] then err_exit "typeset +n doesn't list values of reference variables" fi -file=/tmp/shtest$$ +file=$tmp/test typeset +n foo bar 2> /dev/null unset foo bar export bar=foo @@ -104,7 +108,6 @@ nameref foo=bar if [[ $foo != foo ]] then err_exit "value of nameref foo != $foo" fi -trap "rm -f $file" EXIT INT cat > $file <<\! print -r -- $foo ! @@ -113,7 +116,7 @@ y=$( $file) if [[ $y != '' ]] then err_exit "reference variable not cleared" fi -{ +{ command nameref xx=yy command nameref yy=xx } 2> /dev/null && err_exit "self reference not detected" @@ -127,7 +130,7 @@ then err_exit 'nameref of positional paramters outside of function not working' fi unset foo bar bar=123 -function foobar +function foobar { typeset -n foo=bar typeset -n foo=bar @@ -216,7 +219,7 @@ function local qs=(integer a=3; integer b=4) } local 2> /dev/null || err_exit 'function local has non-zero exit status' -[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable' +[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable' unset fun i foo=(x=hi) function fun @@ -297,4 +300,66 @@ vars=(data=()) vars.data._1.a=a.1 vars.data._1.b=b.1 [[ $(a) == 'a.1 b.1' ]] || err_exit 'nameref choosing wrong scope -- ' +typeset +n bam zip foo +unset bam zip foo +typeset -A foo +foo[2]=bar +typeset -n bam=foo[2] +typeset -n zip=bam +[[ $zip == bar ]] || err_exit 'nameref to another nameref to array element fails' +[[ -R zip ]] || err_exit '[[ -R zip ]] should detect that zip is a reference' +[[ -R bam ]] || err_exit '[[ -R bam ]] should detect that bam is a reference' +[[ -R zip ]] || err_exit '[[ -v zip ]] should detect that zip is set' +[[ -v bam ]] || err_exit '[[ -v bam ]] should detect that bam is set' +[[ -R 123 ]] && err_exit '[[ -R 123 ]] should detect that 123 is not a reference' +[[ -v 123 ]] && err_exit '[[ -v 123 ]] should detect that 123 is not set' + +unset ref x +typeset -n ref +x=3 +function foobar +{ + typeset xxx=3 + ref=xxx + return 0 +} +foobar 2> /dev/null && err_exit 'invalid reference should cause foobar to fail' +[[ -v ref ]] && err_exit '$ref should be unset' +ref=x +[[ $ref == 3 ]] || err_exit "\$ref is $ref, it should be 3" +function foobar +{ + typeset fvar=() + typeset -n ref=fvar.foo + ref=ok + print -r $ref +} +[[ $(foobar) == ok ]] 2> /dev/null || err_exit 'nameref in function not creating variable in proper scope' +function foobar +{ + nameref doc=docs + nameref bar=doc.num + [[ $bar == 2 ]] || err_exit 'nameref scoping error' +} + +docs=(num=2) +foobar + +typeset +n x y +unset x y +typeset -A x +x[a]=(b=c) +typeset -n y=x[a] +[[ ${!y.@} == 'x[a].b' ]] || err_exit 'reference to array element not expanded with ${!y.@}' + +typeset +n v +v=() +k=a.b.c/d +command typeset -n n=v.${k//['./']/_} 2> /dev/null || err_exit 'patterns with quotes not handled correctly with name reference assignment' + +typeset _n sp +nameref sp=addrsp +sp[14]=( size=1 ) +[[ -v sp[19] ]] && err_exit '[[ -v sp[19] ]] where sp is a nameref should not be set' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/options.sh b/usr/src/lib/libshell/common/tests/options.sh index 07608efa1e..cebb405a27 100644 --- a/usr/src/lib/libshell/common/tests/options.sh +++ b/usr/src/lib/libshell/common/tests/options.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -29,11 +29,17 @@ Command=${0##*/} integer Errors=0 unset HISTFILE +export LC_ALL=C ENV= + +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT if [[ $( ${SHELL-ksh} -s hello<<-\! print $1 ! - ) != hello ]] + ) != hello ]] then err_exit "${SHELL-ksh} -s not working" fi x=$( @@ -42,102 +48,118 @@ x=$( print good ) if [[ $x != good ]] -then err_exit 'sh -e not workuing' +then err_exit 'sh -e not working' fi [[ $($SHELL -D -c 'print hi; print $"hello"') == '"hello"' ]] || err_exit 'ksh -D not working' -tmp=/tmp/ksh$$ -mkdir $tmp +env=$tmp/.env +print $'(print -u1 aha) &>/dev/null\n(print -u2 aha) &>/dev/null' > $env rc=$tmp/.kshrc print $'PS1=""\nfunction env_hit\n{\n\tprint OK\n}' > $rc -export ENV='${nosysrc}'$rc +export ENV=/.$env +if [[ ! -o privileged ]] +then + got=$($SHELL -E -c : 2>/dev/null) + if [[ $g ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got" + fi + got=$($SHELL -E -c : 2>&1 >/dev/null) + if [[ $got != *nonstandard* || $got == *$'\n'* ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stderr -- expected one diagnostic line, got $got" + fi +fi + +export ENV=/.$rc if [[ -o privileged ]] then - [[ $(print env_hit | $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $ENV file' - [[ $(print env_hit | $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E reads $ENV file' - [[ $(print env_hit | $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $ENV file' - [[ $(print env_hit | $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc reads $ENV file' - [[ $(print env_hit | $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $ENV file' else - [[ $(print env_hit | $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $ENV file' - [[ $(print env_hit | $SHELL -E 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] || err_exit '-E ignores $ENV file' - [[ $(print env_hit | $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $ENV file' - [[ $(print env_hit | $SHELL --rc 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] || err_exit '--rc ignores $ENV file' - [[ $(print env_hit | $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $ENV file' - [[ $(print env_hit | $SHELL -i 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | $SHELL -i 2>&1) == "OK" ]] || err_exit '-i ignores $ENV file' fi export ENV= if [[ -o privileged ]] then - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $HOME/.kshrc file' else - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit '-E ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit '--rc ignores empty $ENV' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $HOME/.kshrc file' fi unset ENV if [[ -o privileged ]] then - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && err_exit 'privileged -E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit 'privileged +E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && err_exit 'privileged --rc reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit 'privileged --norc reads $HOME/.kshrc file' else - [[ $(print env_hit | HOME=$tmp $SHELL 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && err_exit 'nointeractive shell reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL -E 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] || err_exit '-E ignores $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL +E 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && err_exit '+E reads $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>/dev/null) == "OK" ]] || + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] || err_exit '--rc ignores $HOME/.kshrc file' - [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>/dev/null) == "OK" ]] && + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && err_exit '--norc reads $HOME/.kshrc file' fi -rm -rf $tmp +rm -rf $tmp/.kshrc if command set -G 2> /dev/null -then mkdir /tmp/ksh$$ - cd /tmp/ksh$$ +then cd $tmp mkdir bar foo - > bar.c > bam.c + > bar.c > bam.c > bar/foo.c > bar/bam.c > foo/bam.c set -- **.c @@ -157,49 +179,48 @@ then mkdir /tmp/ksh$$ [[ $* == $expected ]] || err_exit "-G **/bam.c failed -- expected '$expected', got '$*'" cd ~- - rm -rf /tmp/ksh$$ fi -mkdir /tmp/ksh$$ -cd /tmp/ksh$$ +cd $tmp t="<$$>.profile.<$$>" echo "echo '$t'" > .profile cp $SHELL ./-ksh if [[ -o privileged ]] then - [[ $(HOME=$PWD $SHELL -l </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] && err_exit 'privileged -l reads .profile' - [[ $(HOME=$PWD $SHELL --login </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login reads .profile' - [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login-shell reads .profile' - [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] && err_exit 'privileged --login_shell reads .profile' - [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] && err_exit 'privileged exec -a -ksh ksh reads .profile' - [[ $(HOME=$PWD ./-ksh -i </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] && err_exit 'privileged ./-ksh reads .profile' - [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && err_exit 'privileged ./-ksh -p reads .profile' else - [[ $(HOME=$PWD $SHELL -l </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] || err_exit '-l ignores .profile' - [[ $(HOME=$PWD $SHELL --login </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] || err_exit '--login ignores .profile' - [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] || err_exit '--login-shell ignores .profile' - [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] || err_exit '--login_shell ignores .profile' - [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] || - err_exit 'exec -a -ksh ksh ignores .profile' - [[ $(HOME=$PWD ./-ksh -i </dev/null 2>/dev/null) == *$t* ]] || + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>/dev/null ignores .profile' + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>&1 ignores .profile' + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] || err_exit './-ksh ignores .profile' - [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>/dev/null) == *$t* ]] && + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && err_exit './-ksh -p does not ignore .profile' fi cd ~- -rm -rf /tmp/ksh$$ - +rm -rf $tmp/.profile # { exec interactive login_shell restricted xtrace } in the following test @@ -333,44 +354,146 @@ set $restore state=$(set --state) [[ $state == "set $restore" ]] || err_exit "set --state after restore failed: expected 'set $restore', got '$state'" -false | true | true || err_exit 'pipe not exiting exit value of last element' -true | true | false && err_exit 'pipe not exiting false' -set -o pipefail -false | true | true && err_exit 'pipe with first not failing with pipefail' -true | false | true && err_exit 'pipe middle not failing with pipefail' -true | true | false && err_exit 'pipe last not failing with pipefail' -print hi | (sleep 1;/bin/cat) > /dev/null || err_exit 'pipeline fails with pipefail' +typeset -a pipeline +pipeline=( + ( nopipefail=0 pipefail=1 command='false|true|true' ) + ( nopipefail=0 pipefail=1 command='true|false|true' ) + ( nopipefail=1 pipefail=1 command='true|true|false' ) + ( nopipefail=1 pipefail=1 command='false|false|false' ) + ( nopipefail=0 pipefail=0 command='true|true|true' ) + ( nopipefail=0 pipefail=0 command='print hi|(sleep 1;/bin/cat)>/dev/null' ) +) +set --nopipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].nopipefail} + [[ $status == $expected ]] || + err_exit "--nopipefail '${pipeline[i].command}' exit status $status -- expected $expected" +done +ftt=0 +set --pipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].pipefail} + if [[ $status != $expected ]] + then err_exit "--pipefail '${pipeline[i].command}' exit status $status -- expected $expected" + (( i == 0 )) && ftt=1 + fi +done +if (( ! ftt )) +then exp=10 + got=$(for((n=1;n<exp;n++))do $SHELL --pipefail -c '(sleep 0.1;false)|true|true' && break; done; print $n) + [[ $got == $exp ]] || err_exit "--pipefail -c '(sleep 0.1;false)|true|true' fails with exit status 0 (after $got/$exp iterations)" +fi + +echo=$(whence -p echo) +for ((i=0; i < 20; i++)) +do if ! x=$(true | $echo 123) + then err_exit 'command substitution with wrong exit status with pipefai' + break + fi +done ( set -o pipefail false | true (( $? )) || err_exit 'pipe not failing in subshell with pipefail' ) | wc >/dev/null $SHELL -c 'set -o pipefail; false | $(whence -p true);' && err_exit 'pipefail not returning failure with sh -c' -[[ $( set -o pipefail +exp='1212 or 1221' +got=$( + set --pipefail pipe() { date | cat > /dev/null ;} print $'1\n2' | - while read i - do if pipe /tmp - then { print enter $i; sleep 2; print leave $i; } & + while read i + do if pipe $tmp + then { print -n $i; sleep 2; print -n $i; } & fi done - wait) == $'enter 1\nenter 2'* ]] || err_exit '& job delayed by pipefail' -$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' -trap 'rm -f /tmp/.profile' EXIT -> /tmp/.profile -for i in i l r s D E a b e f h k n r t u v x B C G H -do HOME=/tmp ENV= $SHELL -$i 2> /dev/null <<- ++EOF++ || err_exit "option $i not in \$-" - [[ \$- == *$i* ]] || exit 1 + wait +) +[[ $got == @((12|21)(12|21)) ]] || err_exit "& job delayed by --pipefail, expected '$exp', got '$got'" +$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' +> $tmp/.profile +for i in i l r s D E a b e f h k n t u v x B C G H +do HOME=$tmp ENV= $SHELL -$i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not in \$-" + [[ \$- == *$i* ]] || exit 1 ++EOF++ done letters=ilrabefhknuvxBCGE integer j=0 -for i in interactive login restricted allexport notify errexit \ - noglob trackall keyword noexec nounset verbose xtrace braceexpand \ +for i in interactive login restricted allexport notify errexit \ + noglob trackall keyword noexec nounset verbose xtrace braceexpand \ noclobber globstar rc -do HOME=/tmp ENV= $SHELL -o $i 2> /dev/null <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" - [[ \$- == *${letters:j:1}* ]] || exit 1 +do HOME=$tmp ENV= $SHELL -o $i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" + [[ \$- == *${letters:j:1}* ]] || exit 1 ++EOF++ ((j++)) done + +export ENV= +histfile=$tmp/history +exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo') +for var in HISTSIZE HISTFILE +do got=$( ( HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 ) + got=${got##*': '} + [[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'" + got=$( { HISTFILE=$histfile $SHELL -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 ) + got=${got##*': '} + [[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'" +done +( unset HISTFILE; $SHELL -ic "HISTFILE=$histfile" 2>/dev/null ) || err_exit "setting HISTFILE when not in environment fails" + +# the next tests loop on all combinations of +# { SUB PAR CMD ADD } + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +PAR=( + ( BEG='( ' END=' )' ) + ( BEG='{ ' END='; }' ) +) +CMD=( command-kill script-kill ) +ADD=( '' '; :' ) + +cd $tmp +print $'#!'$SHELL$'\nkill -KILL $$' > command-kill +print $'kill -KILL $$' > script-kill +chmod +x command-kill script-kill +export PATH=.:$PATH +exp='Killed' +for ((S=0; S<${#SUB[@]}; S++)) +do for ((P=0; P<${#PAR[@]}; P++)) + do for ((C=0; C<${#CMD[@]}; C++)) + do for ((A=0; A<${#ADD[@]}; A++)) + do cmd="${SUB[S].BEG}${PAR[P].BEG}${CMD[C]}${PAR[P].END} 2>&1${ADD[A]}${SUB[S].END}" + eval got="$cmd" + got=${got##*': '} + got=${got%%'('*} + [[ $got == "$exp" ]] || err_exit "$cmd failed -- got '$got', expected '$exp'" + done + done + done +done + +$SHELL 2> /dev/null -c '{; true ;}' || err_exit 'leading ; causes syntax error in brace group' +$SHELL 2> /dev/null -c '(; true ;)' || err_exit 'leading ; causes syntax error in parenthesis group' + +print 'for ((i = 0; i < ${1:-10000}; i++ )); do printf "%.*c\n" 15 x; done' > pipefail +chmod +x pipefail +$SHELL --pipefail -c './pipefail 10000 | sed 1q' >/dev/null 2>&1 & +tst=$! +{ sleep 4; kill $tst; } 2>/dev/null & +spy=$! +wait $tst 2>/dev/null +status=$? +if [[ $status == 0 || $(kill -l $status) == PIPE ]] +then kill $spy 2>/dev/null +else err_exit "pipefail pipeline bypasses SIGPIPE and hangs" +fi +wait + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/path.sh b/usr/src/lib/libshell/common/tests/path.sh index 2e46e2bd48..edf7621663 100644 --- a/usr/src/lib/libshell/common/tests/path.sh +++ b/usr/src/lib/libshell/common/tests/path.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,12 +24,14 @@ function err_exit let Errors+=1 } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ -cd /tmp/ksh$$ -trap "PATH=$PATH; cd /; rm -rf /tmp/ksh$$" EXIT +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || exit type /xxxxxx > out1 2> out2 [[ -s out1 ]] && err_exit 'type should not write on stdout for not found case' [[ -s out2 ]] || err_exit 'type should write on stderr for not found case' @@ -69,37 +71,36 @@ PATH=$FPATH:$p PATH=$p (PATH="/bin") [[ $($SHELL -c 'print -r -- "$PATH"') == "$PATH" ]] || err_exit 'export PATH lost in subshell' -cat > bug1 <<- \EOF - print print ok > /tmp/ok$$ - /bin/chmod 755 /tmp/ok$$ - trap 'cd /; rm -f /tmp/ok$$' EXIT +cat > bug1 <<- EOF + print print ok > $tmp/ok + /bin/chmod 755 $tmp/ok function a { - typeset -x PATH=/tmp - ok$$ + typeset -x PATH=$tmp + ok } - path=$PATH + path=\$PATH unset PATH a - PATH=$path + PATH=\$path } EOF -[[ $($SHELL ./bug1 2> /dev/null) == ok ]] || err_exit "PATH in function not working" +[[ $($SHELL ./bug1 2>/dev/null) == ok ]] || err_exit "PATH in function not working" cat > bug1 <<- \EOF function lock_unlock { typeset PATH=/usr/bin typeset -x PATH='' } - + PATH=/usr/bin : $(PATH=/usr/bin getconf PATH) typeset -ft lock_unlock lock_unlock EOF ($SHELL ./bug1) 2> /dev/null || err_exit "path_delete bug" -mkdir tdir$$ -if $SHELL tdir$$ > /dev/null 2>&1 +mkdir tdir +if $SHELL tdir > /dev/null 2>&1 then err_exit 'not an error to run ksh on a directory' fi @@ -121,7 +122,7 @@ var=$(whence date) dir=$(basename "$var") for i in 1 2 3 4 5 6 7 8 9 0 do if ! whence notfound$i 2> /dev/null - then cmd=notfound$i + then cmd=notfound$i break fi done @@ -132,7 +133,7 @@ chmod +x "$cmd" > foo chmod 755 foo for PATH in $path :$path $path: .:$path $path: $path:. $PWD::$path $PWD:.:$path $path:$PWD $path:.:$PWD -do +do # print path=$PATH $(whence date) # print path=$PATH $(whence "$cmd") date @@ -155,19 +156,60 @@ fi status=$? [[ $status == 126 ]] || err_exit "exit status of non-executable is $status -- 126 expected" builtin -d rm 2> /dev/null +chmod=$(whence chmod) rm=$(whence rm) d=$(dirname "$rm") + +chmod=$(whence chmod) + +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(unset FPATH; PATH=/dev/null; whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence $cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(unset FPATH; PATH=/dev/null; whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done + +exp='' +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence ./notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence $PWD/notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + unset FPATH PATH=/dev/null -if date > /dev/null 2>&1 -then err_exit 'programs in . should not be found' -fi -[[ $(whence ./foo) != "$PWD/"./foo ]] && err_exit 'whence ./foo not working' -[[ $(whence "$PWD/foo") != "$PWD/foo" ]] && err_exit 'whence $PWD/foo not working' -[[ $(whence ./xxxxx) ]] && err_exit 'whence ./xxxx not working' +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($cmd 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($cmd 2>&1; :) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence ./$cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done +exp='' +got=$(whence ./notfound) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$(whence $PWD/notfound) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + PATH=$d: -cp "$rm" kshrm$$ -if [[ $(whence kshrm$$) != $PWD/kshrm$$ ]] +cp "$rm" kshrm +if [[ $(whence kshrm) != $PWD/kshrm ]] then err_exit 'trailing : in pathname not working' fi cp "$rm" rm @@ -196,7 +238,7 @@ then PATH= then err_exit 'unsetting path not working' fi fi -PATH=/dev:/tmp/ksh$$ +PATH=/dev:$tmp x=$(whence rm) typeset foo=$(PATH=/xyz:/abc :) y=$(whence rm) @@ -212,11 +254,11 @@ PATH=$PWD:.:${x%/ls} [[ $(whence ls) == "$x" ]] || err_exit 'PATH search bug when :$PWD:. in path' cd "${x%/ls}" [[ $(whence ls) == /* ]] || err_exit 'whence not generating absolute pathname' -status=$($SHELL -c $'trap \'print $?\' EXIT;/a/b/c/d/e 2> /dev/null') +status=$($SHELL -c $'trap \'print $?\' EXIT;/xxx/a/b/c/d/e 2> /dev/null') [[ $status == 127 ]] || err_exit "not found command exit status $status -- expected 127" status=$($SHELL -c $'trap \'print $?\' EXIT;/dev/null 2> /dev/null') [[ $status == 126 ]] || err_exit "non executable command exit status $status -- expected 126" -status=$($SHELL -c $'trap \'print $?\' ERR;/a/b/c/d/e 2> /dev/null') +status=$($SHELL -c $'trap \'print $?\' ERR;/xxx/a/b/c/d/e 2> /dev/null') [[ $status == 127 ]] || err_exit "not found command with ERR trap exit status $status -- expected 127" status=$($SHELL -c $'trap \'print $?\' ERR;/dev/null 2> /dev/null') [[ $status == 126 ]] || err_exit "non executable command ERR trap exit status $status -- expected 126" @@ -231,7 +273,7 @@ getconf UNIVERSE - att # override sticky default 'UNIVERSE = foo' PATH=$path -scr=/tmp/ksh$$/foo +scr=$tmp/script exp=126 : > $scr diff --git a/usr/src/lib/libshell/common/tests/pointtype.sh b/usr/src/lib/libshell/common/tests/pointtype.sh index 25b9f5fbc5..28b60c499c 100644 --- a/usr/src/lib/libshell/common/tests/pointtype.sh +++ b/usr/src/lib/libshell/common/tests/pointtype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/quoting.sh b/usr/src/lib/libshell/common/tests/quoting.sh index b15739da08..a1df26a230 100644 --- a/usr/src/lib/libshell/common/tests/quoting.sh +++ b/usr/src/lib/libshell/common/tests/quoting.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -212,12 +212,12 @@ fi foo=bar bar=$(print -r -- ${foo+\\n\ }) if [[ $bar != '\n ' ]] -then err_exit '${foo+\\n\ } expansion error' +then err_exit '${foo+\\n\ } expansion error' fi unset bar bar=$(print -r -- ${foo+\\n\ $bar}) if [[ $bar != '\n ' ]] -then err_exit '${foo+\\n\ $bar} expansion error with bar unset' +then err_exit '${foo+\\n\ $bar} expansion error with bar unset' fi x='\\(..\\)|&\|\|\\&\\|' if [[ $(print -r -- $x) != "$x" ]] @@ -326,7 +326,7 @@ string='&foo' { x=x x=${x:-`id | sed 's/^[^(]*(\([^)]*\)).*/\1/'`} -} 2> /dev/null || err_exit 'skipping over `` failed' +} 2> /dev/null || err_exit 'skipping over `` failed' [[ $x == x ]] || err_exit 'assignment ${x:=`...`} failed' [[ $($SHELL -c 'print a[') == 'a[' ]] || err_exit "unbalanced '[' in command arg fails" $SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;:' 2> /dev/null || err_exit 'syntax error with ` in arithmetic expression' @@ -334,4 +334,9 @@ $SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;: varname=foobarx x=`print '"\$'${varname}'"'` [[ $x == '"$foobarx"' ]] || err_exit $'\\$\' not handled correctly inside ``' + +copy1=5 copynum=1 +foo="`eval echo "$"{copy$copynum"-0}"`" +[[ $foo == "$copy1" ]] || err_exit '$"..." not being ignored inside ``' + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/quoting2.sh b/usr/src/lib/libshell/common/tests/quoting2.sh index 334ed40e7c..dab0992f6b 100644 --- a/usr/src/lib/libshell/common/tests/quoting2.sh +++ b/usr/src/lib/libshell/common/tests/quoting2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -197,11 +197,13 @@ foo=foo [[ "$" == '$' ]] || err_exit '"$" != $' [[ "${foo}$" == 'foo$' ]] || err_exit 'foo=foo;"${foo}$" != foo$' [[ "${foo}${foo}$" == 'foofoo$' ]] || err_exit 'foo=foo;"${foo}${foo}$" != foofoo$' -foo='$ ' +foo='$ ' [[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'$ \' not matching RE \\\\\\$|#\'' -[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' foo='# ' -[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' [[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'# \' not matching RE \'\\$\'|#\'' [[ '\$' == '\$'* ]] || err_exit $'\'\\$\' not matching \'\\$\'*' +[[ a+a == ~(E)a\+a ]] || err_exit '~(E)a\+a not matching a+a' +[[ a+a =~ a\+a ]] || err_exit 'RE a\+a not matching a+a' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/recttype.sh b/usr/src/lib/libshell/common/tests/recttype.sh index 8fe1f3d4ff..b2bca80f50 100644 --- a/usr/src/lib/libshell/common/tests/recttype.sh +++ b/usr/src/lib/libshell/common/tests/recttype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/restricted.sh b/usr/src/lib/libshell/common/tests/restricted.sh index 9cc28c7303..eca93ce6f2 100644 --- a/usr/src/lib/libshell/common/tests/restricted.sh +++ b/usr/src/lib/libshell/common/tests/restricted.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,11 +25,13 @@ function err_exit } alias err_exit='err_exit $LINENO' -# test restricted shell Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap "cd /; rm -rf /tmp/ksh$$" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test restricted shell pwd=$PWD case $SHELL in /*) ;; @@ -40,14 +42,14 @@ function check_restricted { rm -f out rksh -c "$@" 2> out > /dev/null - grep restricted out > /dev/null 2>&1 + grep restricted out > /dev/null 2>&1 } [[ $SHELL != /* ]] && SHELL=$pwd/$SHELL -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +cd $tmp || err_exit "cd $tmp failed" ln -s $SHELL rksh PATH=$PWD:$PATH -rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' +rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' [[ $(rksh -c 'print hello') == hello ]] || err_exit 'unable to run print' check_restricted /bin/echo || err_exit '/bin/echo not resticted' check_restricted ./echo || err_exit './echo not resticted' @@ -74,4 +76,7 @@ print hello ! ! check_restricted 'script;:' || err_exit 'script with #! pathname should run in restricted mode' ! check_restricted 'script' || err_exit 'script with #! pathname should run in restricted mode even if last command in script' +for i in PATH ENV FPATH +do check_restricted "function foo { typeset $i=foobar;};foo" || err_exit "$i can be changed in function by using typeset" +done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/return.sh b/usr/src/lib/libshell/common/tests/return.sh index ac9d2761c0..c9bbf0f33c 100644 --- a/usr/src/lib/libshell/common/tests/return.sh +++ b/usr/src/lib/libshell/common/tests/return.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -26,14 +26,17 @@ function err_exit let Errors+=1 } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + unset HISTFILE foo=NOVAL bar=NOVAL -file=/tmp/shtest$$ -trap "rm -f $file" EXIT INT +file=$tmp/test function foo { typeset foo=NOEXIT @@ -125,7 +128,7 @@ then err_exit "return in script is $ret should be 3" fi cat > $file <<! : line 1 -# next line should fail and cause an exit +# next line should fail and cause an exit : > / exit 4 ! diff --git a/usr/src/lib/libshell/common/tests/select.sh b/usr/src/lib/libshell/common/tests/select.sh index 578fca2e11..2728f85a40 100644 --- a/usr/src/lib/libshell/common/tests/select.sh +++ b/usr/src/lib/libshell/common/tests/select.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,10 +27,13 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -trap "rm -f /tmp/Sh$$*" EXIT + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + PS3='ABC ' -cat > /tmp/Sh$$.1 <<\! +cat > $tmp/1 <<\! 1) foo 2) bar 3) bam @@ -57,7 +60,7 @@ do case $i in ( set -u; : $i ) || err_exit "select: i not set to null" 2>&3 break;; esac -done 3>&2 2> /tmp/Sh$$.2 <<! +done 3>&2 2> $tmp/2 <<! foo ! exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/shtests b/usr/src/lib/libshell/common/tests/shtests index 63b8db0462..37a36c29ef 100644 --- a/usr/src/lib/libshell/common/tests/shtests +++ b/usr/src/lib/libshell/common/tests/shtests @@ -1,13 +1,15 @@ # This program runs ksh regression tests # shtests [ name=value ... ] [ --all | --compile ] [ --time ] [ a.sh b.sh ... ] -unset DISPLAY ENV FIGNORE +timesensitive='*@(options|sigchld|subshell).sh' + +unset DISPLAY ENV FIGNORE HISTFILE LANG=C LC_ALL=C compile=1 script=1 time=1 -vmdebug=1 +vmdebug=a while : do case $1 in -a|--a*)compile=2 @@ -38,9 +40,11 @@ do case $1 in done if [[ ! $vmdebug ]] then unset VMDEBUG -elif [[ ! $VMDEBUG ]] -then export VMDEBUG=a +elif [[ $VMDEBUG ]] +then vmdebug=$VMDEBUG +else export VMDEBUG=$vmdebug fi +[[ $VMDEBUG ]] || timesensitive=. export LANG LC_ALL PATH PWD SHELL PWD=`pwd` SHELL=${SHELL-ksh} @@ -65,9 +69,8 @@ fi if [[ $compile ]] then SHCOMP=${SHCOMP:-shcomp} if whence $SHCOMP > /dev/null - then tmp=/tmp/ksh-$$ - trap 'rm -rf $tmp' EXIT - mkdir $tmp || exit + then tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; } + trap "cd /; rm -rf $tmp" EXIT elif [[ $compile != 1 ]] then echo $0: --compile: $SHCOMP not found >&2 exit 1 @@ -88,6 +91,9 @@ do t=$(grep -c err_exit $i) E=error if [[ $script ]] then echo test $i begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + if [[ $i == $timesensitive ]] + then unset VMDEBUG + fi if $SHELL $i then echo test $i passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" else e=$? @@ -100,6 +106,9 @@ do t=$(grep -c err_exit $i) fi echo test $i failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi + if [[ $i == $timesensitive ]] + then export VMDEBUG=$vmdebug + fi fi done if [[ $compile ]] @@ -114,7 +123,10 @@ then for i in ${*-*.sh} echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} E=error if $SHCOMP $i > $tmp/$o - then if $SHELL $tmp/$o + then if [[ $i == $timesensitive ]] + then unset VMDEBUG + fi + if $SHELL $tmp/$o then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" else e=$? if (( e > 256 )) @@ -126,6 +138,9 @@ then for i in ${*-*.sh} fi echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" fi + if [[ $i == $timesensitive ]] + then export VMDEBUG=$vmdebug + fi else e=$? t=1 T=test diff --git a/usr/src/lib/libshell/common/tests/sigchld.sh b/usr/src/lib/libshell/common/tests/sigchld.sh index 018eb9fbc0..0b2bf8e03f 100644 --- a/usr/src/lib/libshell/common/tests/sigchld.sh +++ b/usr/src/lib/libshell/common/tests/sigchld.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -59,7 +59,55 @@ print foreground=$foreground background=$background eval $s -(( foreground == FOREGROUND )) || err_exit "expected $FOREGROUND foreground -- got $foreground (DELAY=$DELAY)" -(( background == BACKGROUND )) || err_exit "expected $BACKGROUND background -- got $background (DELAY=$DELAY)" +(( foreground == FOREGROUND )) || err_exit "expected '$FOREGROUND foreground' -- got '$foreground' (DELAY=$DELAY)" +(( background == BACKGROUND )) || err_exit "expected '$BACKGROUND background' -- got '$background' (DELAY=$DELAY)" + +set --noerrexit + +if [[ ${.sh.version} == Version?*([[:upper:]])J* ]] +then + + jobmax=4 + got=$($SHELL -c ' + JOBMAX='$jobmax' JOBCOUNT=$(('$jobmax'*2)) + integer running=0 maxrunning=0 + trap "((running--))" CHLD + for ((i=0; i<JOBCOUNT; i++)) + do sleep 1 & + if ((++running > maxrunning)) + then ((maxrunning=running)) + fi + done + wait + print running=$running maxrunning=$maxrunning + ') + exp='running=0 maxrunning='$jobmax + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected '$exp', got '$got'" + + got=$($SHELL -c ' + typeset -A proc + + trap " + print \${proc[\$!].name} \${proc[\$!].status} \$? + unset proc[\$!] + " CHLD + + { sleep 3; print a; exit 1; } & + proc[$!]=( name=a status=1 ) + + { sleep 2; print b; exit 2; } & + proc[$!]=( name=b status=2 ) + + { sleep 1; print c; exit 3; } & + proc[$!]=( name=c status=3 ) + + while (( ${#proc[@]} )) + do sleep -s + done + ') + exp='c\nc 3 3\nb\nb 2 2\na\na 1 1' + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected $(printf %q "$exp"), got $(printf %q "$got")" + +fi exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/signal.sh b/usr/src/lib/libshell/common/tests/signal.sh index 12b06d6fca..bab844fc4d 100644 --- a/usr/src/lib/libshell/common/tests/signal.sh +++ b/usr/src/lib/libshell/common/tests/signal.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,14 +28,39 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 -mkdir /tmp/ksh$$ || err_exit "mkdir /tmp/ksh$$ failed" -trap 'cd /; rm -rf /tmp/ksh$$' EXIT -cd /tmp/ksh$$ || err_exit "cd /tmp/ksh$$ failed" +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || err_exit "cd $tmp failed" + +( + set --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 $?" + [[ $(<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" +fi +wait +rm -f out2 [[ $( trap 'print -n got_child' SIGCHLD sleep 2 & for ((i=0; i < 4; i++)) - do sleep .9 + do sleep .75 print -n $i done) == 01got_child23 ]] || err_exit 'SIGCHLD not working' @@ -55,7 +80,8 @@ cat > tst <<'!' # # 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 exit 0, otherwise SIGINT default +# 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 ... @@ -71,7 +97,7 @@ set -o monitor function gen { typeset o t x d - for x in - x + for x in - x z do case $x in [$1]) for t in - t do case $t in @@ -153,6 +179,11 @@ sleep 2 ! cat > tst-2 <<'!' case $1 in +*z*) trap ' + echo 2-intr + exit 0 + ' INT + ;; *x*) trap ' echo 2-intr exit @@ -176,7 +207,7 @@ printf '2-%04d\n' $status ! cat > tst-3 <<'!' case $1 in -*x*) trap ' +*[xz]*) trap ' sleep 2 echo 3-intr exit 0 @@ -206,10 +237,14 @@ 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[x--]="3-intr 2-intr" +expected[x-d]="3-intr 2-intr" +expected[xt-]="3-intr 2-intr 1-intr 1-0258" +expected[xtd]="3-intr 2-intr 1-intr 1-0258" +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 @@ -218,9 +253,71 @@ do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- ex done < tst.got float s=$SECONDS -[[ $($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' +[[ $($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)) -[[ $($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' +[[ $($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' + +unset n s t +for s in $(kill -l) +do if ! n=$(kill -l $s 2>/dev/null) + then err_exit "'kill -l $s' failed" + continue + fi + if ! t=$(kill -l $n 2>/dev/null) + then err_exit "'kill -l $n' failed" + continue + fi + if [[ $s == ?(SIG)$t ]] + then continue + fi + if ! m=$(kill -l $t 2>/dev/null) + then err_exit "'kill -l $t' failed" + continue + fi + if [[ $m == $n ]] + then continue + fi + err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n" +done +yes=$(whence -p yes) +[[ $yes ]] && for exp in TERM VTALRM PIPE +do { $SHELL <<- EOF + foo() { return 0; } + trap foo EXIT + { sleep 2; kill -$exp \$\$; sleep 3; kill -0 \$\$ && kill -KILL \$\$; } & + $yes | while read yes; do + (/bin/date; sleep .1) + done > /dev/null + EOF + } 2>> /dev/null + got=$(kill -l $?) + [[ $exp == $got ]] || err_exit "kill -$exp \$\$ failed, required termination by signal '$got'" +done + +SECONDS=0 +$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished' > $tmp/sig +(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" + +SECONDS=0 +{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit" EXIT; (sleep 5);print finished' > $tmp/sig ;} 2> /dev/null +[[ $(kill -l $?) == TERM ]] || err_exit "wrong exit status expecting TERM got $(kill -l $?)" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expecting around 2" + +SECONDS=0 +x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done;exit 3" EXIT; (sleep 5);print finished') +(( $?==3)) || err_exit "wrong exit status expecting 3 got $?" +[[ $x == done ]] || err_exit "wrong result - execting done got $x" +(( SECONDS < 4 )) && err_exit "took $SECONDS seconds, expecting around 5" + +trap '' SIGBUS +[[ $($SHELL -c 'trap date SIGBUS;trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap' +trap -- - SIGBUS + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/statics.sh b/usr/src/lib/libshell/common/tests/statics.sh index d6af9c7c91..21175c08db 100644 --- a/usr/src/lib/libshell/common/tests/statics.sh +++ b/usr/src/lib/libshell/common/tests/statics.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -30,9 +30,9 @@ function testfunc typeset cmd="$2" typeset expected_output="$3" typeset output - + output="$($SHELL -c "${cmd}" 2>&1 )" - + [[ "${output}" != "${expected_output}" ]] && err_exit2 ${line_number} "${output} != ${expected_output}" } alias testfunc='testfunc $LINENO' @@ -60,9 +60,9 @@ testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; function l { typeset -S s=( a=0 b=0 ) - + (( s.a++, s.b++ )) - + $1 && printf 'a=%d, b=%d\n' s.a s.b } l false ; l false ; l true @@ -75,9 +75,9 @@ got=$( function ar { typeset -a -S s=( "hello" ) - + s+=( "an element" ) - + $1 && { printf '%s' "${s[@]}" ; printf '\n' ; } } ar false ; ar false ; ar true diff --git a/usr/src/lib/libshell/common/tests/subshell.sh b/usr/src/lib/libshell/common/tests/subshell.sh index 985aba6eaa..bc63bde995 100644 --- a/usr/src/lib/libshell/common/tests/subshell.sh +++ b/usr/src/lib/libshell/common/tests/subshell.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -24,9 +24,15 @@ function err_exit (( Errors+=1 )) } alias err_exit='err_exit $LINENO' + Command=${0##*/} integer Errors=0 Error_fd=2 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +bincat=$(PATH=$(getconf PATH) whence -p cat) + z=() z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) z.bar[0]=hello @@ -70,7 +76,7 @@ false [[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working' ) [[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' - + x=( foo=( qqq=abc rrr=def) bar=( zzz=no rst=fed) @@ -97,8 +103,6 @@ while whence $TEST_notfound >/dev/null 2>&1 do TEST_notfound=notfound-$RANDOM done -tmp=/tmp/kshsubsh$$ -trap "rm -f $tmp" EXIT integer BS=1024 nb=64 ss=60 bs no for bs in $BS 1 do $SHELL -c ' @@ -109,8 +113,8 @@ do $SHELL -c ' set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs') print ${#1} kill $! - ' > $tmp 2>/dev/null - no=$(<$tmp) + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}" done # this time with redirection on the trailing command @@ -124,8 +128,8 @@ do $SHELL -c ' set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null) print ${#1} kill $! - ' > $tmp 2>/dev/null - no=$(<$tmp) + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}" done @@ -220,4 +224,230 @@ do for TEST_exec in '' 'exec' done done +$SHELL -c '( autoload xxxxx);print -n' || err_exit 'autoloaded functions in subshells can cause failure' +foo=$($SHELL <<- ++EOF++ + (trap 'print bar' EXIT;print -n foo) + ++EOF++ +) +[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered' + +err=$( + $SHELL 2>&1 <<- \EOF + date=$(whence -p date) + function foo + { + x=$( $date > /dev/null 2>&1 ;:) + } + # consume almost all fds to push the test to the fd limit # + integer max=$(ulimit --nofile) + (( max -= 6 )) + for ((i=20; i < max; i++)) + do exec {i}>&1 + done + for ((i=0; i < 20; i++)) + do y=$(foo) + done + EOF +) || { + err=${err%%$'\n'*} + err=${err#*:} + err=${err##[[:space:]]} + err_exit "nested command substitution with redirections failed -- $err" +} + +exp=0 +$SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + exit '$exp$' +' +got=$? +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" +exp=ok +got=$($SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + print '$exp$' +') +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" + +# command substitution variations # +set -- \ + '$(' ')' \ + '${ ' '; }' \ + '$(ulimit -c 0; ' ')' \ + '$( (' ') )' \ + '${ (' '); }' \ + '`' '`' \ + '`(' ')`' \ + '`ulimit -c 0; ' '`' \ + # end of table # +exp=ok +testcase[1]=' + if %sexpr "NOMATCH" : ".*Z" >/dev/null%s + then print error + else print ok + fi + exit %s +' +testcase[2]=' + function bar + { + pipeout=%1$sprintf Ok | tr O o%2$s + print $pipeout + return 0 + } + foo=%1$sbar%2$s || foo="exit status $?" + print $foo + exit %3$s +' +while (( $# >= 2 )) +do for ((TEST=1; TEST<=${#testcase[@]}; TEST++)) + do body=${testcase[TEST]} + for code in 0 2 + do got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 } + status=$? + if (( status != code )) + then err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code" + elif [[ $got != $exp ]] + then err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'" + fi + done + done + shift 2 +done + +# the next tests loop on all combinations of +# { SUB CAT INS TST APP } X { file-sizes } +# where the file size starts at 1Ki and doubles up to and including 1Mi +# +# the tests and timeouts are done in async subshells to prevent +# the test harness from hanging + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +CAT=( cat $bincat ) +INS=( "" "builtin cat; " "builtin -d cat $bincat; " ": > /dev/null; " ) +APP=( "" "; :" ) +TST=( + ( CMD='print foo | $cat' EXP=3 ) + ( CMD='$cat < $tmp/lin' ) + ( CMD='cat $tmp/lin | $cat' ) + ( CMD='read v < $tmp/buf; print $v' LIM=4*1024 ) + ( CMD='cat $tmp/buf | read v; print $v' LIM=4*1024 ) +) + +command exec 3<> /dev/null +if cat /dev/fd/3 >/dev/null 2>&1 +then T=${#TST[@]} + TST[T].CMD='$cat <(print foo)' + TST[T].EXP=3 +fi + +# prime the two data files to 512 bytes each +# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines +# the outer loop doubles the file size at top + +buf=$'1234567890abcdef' +lin=$'\n1234567890abcde' +for ((i=0; i<5; i++)) +do buf=$buf$buf + lin=$lin$lin +done +print -n "$buf" > $tmp/buf +print -n "$lin" > $tmp/lin + +unset SKIP +for ((n=1024; n<=1024*1024; n*=2)) +do cat $tmp/buf $tmp/buf > $tmp/tmp + mv $tmp/tmp $tmp/buf + cat $tmp/lin $tmp/lin > $tmp/tmp + mv $tmp/tmp $tmp/lin + for ((S=0; S<${#SUB[@]}; S++)) + do for ((C=0; C<${#CAT[@]}; C++)) + do cat=${CAT[C]} + for ((I=0; I<${#INS[@]}; I++)) + do for ((A=0; A<${#APP[@]}; A++)) + do for ((T=0; T<${#TST[@]}; T++)) + do #undent...# + + if [[ ! ${SKIP[S][C][I][A][T]} ]] + then eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &" + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) + if [[ ! $got ]] && (( h )) + then got=HUNG + fi + if [[ ${TST[T].EXP} ]] + then exp=${TST[T].EXP} + else exp=$n + fi + if [[ $got != $exp ]] + then # on failure skip similar tests on larger files sizes # + SKIP[S][C][I][A][T]=1 + siz=$(printf $'%#i' $exp) + cmd=${TST[T].CMD//\$cat/$cat} + cmd=${cmd//\$tmp\/buf/$siz.buf} + cmd=${cmd//\$tmp\/lin/$siz.lin} + err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'" + elif [[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n )) + then SKIP[S][C][I][A][T]=1 + fi + fi + + #...indent# + done + done + done + done + done +done + +# specifics -- there's more? + +{ + cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &' + eval $cmd + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) +} 2>/dev/null +exp='' +if [[ ! $got ]] && (( h )) +then got=HUNG +fi +if [[ $got != $exp ]] +then err_exit "eval '$cmd' failed -- expected '$exp', got '$got'" +fi + +float t1=$SECONDS +sleep=$(whence -p sleep) +if [[ $sleep ]] +then + $SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat + (( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging' + ((t1=SECONDS)) +fi +$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat +(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging' + exit $Errors diff --git a/usr/src/lib/libshell/common/tests/substring.sh b/usr/src/lib/libshell/common/tests/substring.sh index 8d283c6a29..0d7fc384a7 100644 --- a/usr/src/lib/libshell/common/tests/substring.sh +++ b/usr/src/lib/libshell/common/tests/substring.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -192,7 +192,7 @@ fi if [[ ${foo//\//_} != one_two_three ]] then err_exit 'escaping / in replacements failed' fi -function myexport +function myexport { nameref var=$1 if (( $# > 1 )) @@ -205,7 +205,7 @@ function myexport typeset val val=$(export | grep "^$1=") print ${val#"$1="} - + } export dgk=base if [[ $(myexport dgk fun) != fun ]] @@ -280,7 +280,7 @@ b='[abc 123 def]' [[ ${b//$a/\1} == 123 ]] || err_exit "\${var/pattern} not working with \[ in pattern" unset foo foo='(win32.i386) ' -[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" +[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" $SHELL -c $'v=\'$(hello)\'; [[ ${v//\'$(\'/-I\'$(\'} == -I"$v" ]]' 2> /dev/null || err_exit "\${var/pattern} not working with \$( as pattern" unset X $SHELL -c '[[ ! ${X[@]:0:300} ]]' 2> /dev/null || err_exit '${X[@]:0:300} with X undefined fails' @@ -303,7 +303,7 @@ done [[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z' : ${string/$pattern/} (( ${#.sh.match[@]} == 53 )) || err_exit '.sh.match has wrong number of elements' -[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect' +[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect' D=$';' E=$'\\\\' Q=$'"' S=$'\'' M='nested pattern substitution failed' @@ -501,7 +501,7 @@ pattern=00 var=100 [[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embeddded patterns fails" [[ $( print $(( ${var%%$pattern} )) ) == 1 ]] || err_exit "arithmetic with embeddded pattern variables fails" -if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]] +if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]] then err_exit '${.sh.match[1]:1:${#.sh.match[1]}} not expanding correctly' fi @@ -509,10 +509,10 @@ string='foo(d:\nt\box\something)bar' expected='d:\nt\box\something' [[ ${string/*\(+([!\)])\)*/\1} == "$expected" ]] || err_exit "substring expansion failed '${string/*\(+([!\)])\)*/\1}' returned -- '$expected' expected" if [[ $($SHELL -c $'export LC_ALL=en_US.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 ]] -then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'Multibyte ${var:offset:len} not working correctly' +then LC_ALL=en_US.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'multibyte ${var:offset:len} not working correctly' fi -{ $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' -{ $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' +{ $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' +{ $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' # subject mode pattern result # set -- \ diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh b/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh new file mode 100644 index 0000000000..45b3851f19 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_array_default_datatype.sh @@ -0,0 +1,303 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test module checks whether indexed+associative arrays +# set the default datatype correctly if someone uses the "+=" +# operator to add a value to an array element which does not +# exist yet. +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +# the test cannot use "nounset" +Command=${0##*/} +integer Errors=0 + +compound bracketstat=( + integer bopen=0 + integer bclose=0 +) + +function count_brackets +{ + typeset x="$1" + typeset c + + integer i + (( bracketstat.bopen=0 , bracketstat.bclose=0 )) + + for (( i=0 ; i < ${#x} ; i++ )) ; do + c="${x:i:1}" + [[ "$c" == "(" ]] && (( bracketstat.bopen++ )) + [[ "$c" == ")" ]] && (( bracketstat.bclose++ )) + done + + (( bracketstat.bopen != bracketstat.bclose )) && return 1 + + return 0 +} + +# function to add the floating-point value 1.1 to array element "34" +# floating-point datatypes should increment by 1.1, integers by 1 +function add_float +{ + nameref arr=$1 + + arr[34]+=1.1 + + return 0 +} + +# function to add a compound variable called "val" to array element arr[34] +function add_compound +{ + nameref arr=$1 + + arr[34]+=( float val=1.1 ) + + return 0 +} + +# We run the tests in multiple cyles: +# First cycle uses a normal compound variable as basis +# Second cycle uses a nameref to a compound variable as basis +# Third cycle uses a nameref to a nameref to a compound variable as basis +for cycle in \ + c1 c2 c3 c4 \ + c2_sub c3_sub c4_sub \ + c2_indexed_array c3_indexed_array c4_indexed_array \ + c2_associative_array c3_associative_array c4_associative_array; do + case ${cycle} in + c1) + compound mycpv + ;; + c2) + compound rootcpv + nameref mycpv=rootcpv + ;; + c3) + compound rootcpv + nameref namereftoroot=rootcpv + nameref mycpv=namereftoroot + ;; + c4) + compound rootcpv + nameref namereftoroot0=rootcpv + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of rootcpv + c2_sub) + compound rootcpv + compound rootcpv.sub + nameref mycpv=rootcpv.sub + ;; + c3_sub) + compound rootcpv + compound rootcpv.sub + nameref namereftoroot=rootcpv.sub + nameref mycpv=namereftoroot + ;; + c4_sub) + compound rootcpv + compound rootcpv.sub + nameref namereftoroot0=rootcpv.sub + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of an indexed array + c2_indexed_array) + compound -a rootcpv + nameref mycpv=rootcpv[4] + ;; + c3_indexed_array) + compound -a rootcpv + nameref namereftoroot=rootcpv[4] + nameref mycpv=namereftoroot + ;; + c4_indexed_array) + compound -a rootcpv + nameref namereftoroot0=rootcpv[4] + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + # same as cX but uses a subvariable of an indexed array + c2_associative_array) + compound -A rootcpv + nameref mycpv=rootcpv["hello world"] + ;; + c3_associative_array) + compound -A rootcpv + nameref namereftoroot=rootcpv["hello world"] + nameref mycpv=namereftoroot + ;; + c4_associative_array) + compound -A rootcpv + nameref namereftoroot0=rootcpv["hello world"] + nameref namereftoroot1=namereftoroot0 + nameref mycpv=namereftoroot1 + ;; + *) + err_exit "${cycle}: Should not happen." + ;; + esac + + + # Test 001: Test indexed floating-point array + float -a mycpv.myindexedfloatarray + + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" + unset mycpv.myindexedfloatarray[34] + (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" + add_float mycpv.myindexedfloatarray + (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" + unset mycpv.myindexedfloatarray[34] + (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" + + + + # Test 002: Test associative floating-point array + float -A mycpv.myassociativefloatarray + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" + unset mycpv.myassociativefloatarray[34] + (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" + add_float mycpv.myassociativefloatarray + (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" + unset mycpv.myassociativefloatarray[34] + (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" + + + + # Test 003: Test indexed integer array + integer -a mycpv.myindexedintegerarray + + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" + unset mycpv.myindexedintegerarray[34] + (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" + add_float mycpv.myindexedintegerarray + (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" + unset mycpv.myindexedintegerarray[34] + (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" + + + + # Test 004: Test associative integer array + integer -A mycpv.myassociativeintegerarray + + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" + unset mycpv.myassociativeintegerarray[34] + (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" + + # 2nd try (we do this to check whether "unset" works properly) + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" + add_float mycpv.myassociativeintegerarray + (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" + unset mycpv.myassociativeintegerarray[34] + (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" + + + + # Test 005: Tested indexed compound variable array + compound -a mycpv.myindexedcompoundarray + add_compound mycpv.myindexedcompoundarray + (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" + # try to add it a 2nd time - since the new element will replace the old + # one the value will _not_ be incremented (or better: The compound + # variable value "val" will be added, not the value of the "val" + # variable) + add_compound mycpv.myindexedcompoundarray + (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" + unset mycpv.myindexedcompoundarray[34] + [[ ! -v mycpv.myindexedcompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myindexedcompoundarray[34].val ]] should return failure, got $?" + (( mycpv.myindexedcompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 0.0" + [[ "${mycpv.myindexedcompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myindexedcompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myindexedcompoundarray[34]}|" + + + + # Test 006: Tested associative compound variable array + compound -A mycpv.myassociativecompoundarray + add_compound mycpv.myassociativecompoundarray + (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" + # try to add it a 2nd time - since the new element will replace the old + # one the value will _not_ be incremented (or better: The compound + # variable value "val" will be added, not the value of the "val" + # variable) + add_compound mycpv.myassociativecompoundarray + (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" + unset mycpv.myassociativecompoundarray[34] + [[ ! -v mycpv.myassociativecompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myassociativecompoundarray[34].val ]] should return failure, got $?" + (( mycpv.myassociativecompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 0.0" + [[ "${mycpv.myassociativecompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myassociativecompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myassociativecompoundarray[34]}|" + + + # check whether the compound variable output is still Ok + count_brackets "${mycpv}" || err_exit "${cycle}: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + count_brackets "$(print -v mycpv)" || err_exit "${cycle}: print -v mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + count_brackets "$(print -C mycpv)" || err_exit "${cycle}: print -C mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + + + # reset + unset mycpv + [[ ! -v mycpv ]] || err_exit "${cycle}: mycpy should not exist" + [[ "${mycpv}" == "" ]] || err_exit "${cycle}: mycpv expected to be empty" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh new file mode 100644 index 0000000000..5dc5f5cce1 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_poll.sh @@ -0,0 +1,72 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Test whether the ksh93/poll builtin works as expected +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +builtin -f libshell.so.1 poll || err_exit "poll builtin not found." + +compound d1=( + compound -A u=( + [y]=( fd=5 events="POLLIN" revents="" ) + [x]=( fd=5 events="POLLIN" revents="" ) + ) +) + +# test 1: +cat /dev/zero | { redirect 5<&0 ; poll -e d1.res -t 5. d1.u ; } || err_exit "poll returned non-zero exit code $?" +[[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not POLLIN" +[[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not POLLIN" +[[ "${d1.res[*]}" == "x y" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y'" + +# test 2: +unset d1.res + +d1.u[z]=( fd=5 events="POLLOUT" revents="" ) +{ poll -e d1.res -t 5. d1.u ; } 5</dev/null 5>/dev/null || err_exit "poll returned non-zero exit code $?" +[[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not 'POLLIN'" +[[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not 'POLLIN'" +[[ "${d1.u[z].revents}" == "POLLOUT|POLLWRNORM" ]] || err_exit "d1.u[z].revents contains '${d1.u[z].revents}', not 'POLLOUT|POLLWRNORM,'" +[[ "${d1.res[*]}" == "x y z" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y z'" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh index d2dc6db883..e80111a538 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_sum.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -29,6 +29,7 @@ # Solaris/SystemV /usr/bin/sum # +# test setup function err_exit { print -u2 -n "\t" @@ -37,9 +38,11 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset Command=${0##*/} integer Errors=0 + typeset x builtin sum || err_exit "sum builtin not found" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh new file mode 100644 index 0000000000..69a7f1a6b9 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_builtin_tail.sh @@ -0,0 +1,446 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Test whether the ksh93/libcmd tail builtin is compatible to +# Solaris/SystemV { /usr/bin/tail, /usr/xpg4/bin/tail } and +# POSIX "tail" +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# common functions +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} + +function waitpidtimeout +{ + integer pid=$1 + float timeout=$2 + float i + float -r STEP=0.5 # const + + (( timeout=timeout/STEP )) + + for (( i=0 ; i < timeout ; i+=STEP )) ; do + isvalidpid ${pid} || break + sleep ${STEP} + done + + return 0 +} + +function myintseq +{ + integer i + float arg1=$1 + float arg2=$2 + float arg3=$3 + + case $# in + 1) + for (( i=1 ; i <= arg1 ; i++ )) ; do + printf "%d\n" i + done + ;; + 2) + for (( i=arg1 ; i <= arg2 ; i++ )) ; do + printf "%d\n" i + done + ;; + 3) + for (( i=arg1 ; i <= arg3 ; i+=arg2 )) ; do + printf "%d\n" i + done + ;; + *) + print -u2 -f "%s: Illegal number of arguments %d\n" "$0" $# + return 1 + ;; + esac + + return 0 +} + +# quote input string but use double-backslash that "err_exit" prints +# the strings correctly +function doublebackslashquote +{ + typeset s + s="$(printf "%q\n" "$1")" + s="${s//\\/\\\\}" + print -r "$s" + return 0 +} + + +# main +builtin mktemp || err_exit "mktemp builtin not found" +builtin rm || err_exit "rm builtin not found" +builtin tail || err_exit "tail builtin not found" + +typeset ocwd +typeset tmpdir + +# create temporary test directory +ocwd="$PWD" +tmpdir="$(mktemp -d "test_sun_solaris_builtin_tail.XXXXXXXX")" || err_exit "Cannot create temporary directory" + +cd "${tmpdir}" || err_exit "cd ${tmpdir} failed." + + +# run tests: + +# test1: basic tests +compound -a testcases=( + ( + name="reverse_n" + input=$'hello\nworld' + compound -A tail_args=( + [legacy]=( argv=( "-r" ) ) + ) + expected_output=$'world\nhello' + ) + ( + name="revlist0n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-0" ) ) + [std_like]=( argv=( "-n" "0" ) ) + ) + expected_output=$'' + ) + ( + name="revlist0nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-0r" ) ) + [std_like]=( argv=( "-n" "0" "-r" ) ) + [long_options]=( argv=( "--lines" "0" "--reverse" ) ) + ) + expected_output=$'' ) + ( + name="revlist1n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-1" ) ) + [std_like]=( argv=( "-n" "1" ) ) + [long_options]=( argv=( "--lines" "1" ) ) + ) + expected_output=$'4' ) + ( + name="revlist1nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-1r" ) ) + [std_like]=( argv=( "-n" "1" "-r" ) ) + [long_options]=( argv=( "--lines" "1" "--reverse" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist2n" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-2" ) ) + [std_like]=( argv=( "-n" "2" ) ) + ) + expected_output=$'3\n4' + ) + ( + name="revlist2nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-2r" ) ) + [std_like]=( argv=( "-n" "2" "-r" ) ) + ) + expected_output=$'4\n3' + ) + ( + name="revlist3nr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "-3r" ) ) + [std_like]=( argv=( "-n" "3" "-r" ) ) + ) + expected_output=$'4\n3\n2' + ) + ( + name="revlist2p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+2" ) ) + [std_like]=( argv=( "-n" "+2" ) ) + ) + expected_output=$'2\n3\n4' + ) + ( + name="revlist2pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+2r" ) ) + [std_like]=( argv=( "-n" "+2" "-r" ) ) + ) + expected_output=$'4\n3\n2' + ) + ( + name="revlist3p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+3" ) ) + [std_like]=( argv=( "-n" "+3" ) ) + ) + expected_output=$'3\n4' + ) + ( + name="revlist3pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+3r" ) ) + [std_like]=( argv=( "-n" "+3" "-r" ) ) + ) + expected_output=$'4\n3' + ) + ( + name="revlist4p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+4" ) ) + [std_like]=( argv=( "-n" "+4" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist4pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+4r" ) ) + [std_like]=( argv=( "-n" "+4" "-r" ) ) + ) + expected_output=$'4' + ) + ( + name="revlist5p" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+5" ) ) + [std_like]=( argv=( "-n" "+5" ) ) + ) + expected_output=$'' + ) + ( + name="revlist5pr" + input=$'1\n2\n3\n4' + compound -A tail_args=( + [legacy]=( argv=( "+5r" ) ) + [std_like]=( argv=( "-n" "+5" "-r" ) ) + ) + expected_output=$'' + ) +) + +for testid in "${!testcases[@]}" ; do + nameref tc=testcases[${testid}] + + for argv_variants in "${!tc.tail_args[@]}" ; do + nameref argv=tc.tail_args[${argv_variants}].argv + output=$( + #set -o pipefail + print -r -- "${tc.input}" | tail "${argv[@]}" + ) || err_exit "test ${tc.name}/${argv_variants}: command failed with exit code $?" + + [[ "${output}" == "${tc.expected_output}" ]] || err_exit "test ${tc.name}/${argv_variants}: Expected $(doublebackslashquote "${tc.expected_output}"), got $(doublebackslashquote "${output}")" + done +done + + +# test2: test "tail -r </etc/profile | rev -l" vs. "cat </etc/profile" +[[ "$(tail -r </etc/profile | rev -l)" == "$( cat /etc/profile )" ]] || err_exit "'tail -r </etc/profile | rev -l' output does not match 'cat /etc/profile'" + + +# test 3: ast-ksh.2009-05-05 "tail" builtin may crash if we pass unsupported long options +$SHELL -o errexit -c 'builtin tail ; print "hello" | tail --attack_of_chicken_monsters' >/dev/null 2>&1 +(( $? == 2 )) || err_exit "expected exit code 2 for unsupported long option, got $?" + + +# test 4: FIFO tests + +# FIFO test functions +# (we use functions here to do propper garbage collection) +function test_tail_fifo_1 +{ + typeset tail_cmd="$1" + integer i + integer tail_pid=-1 + + # cleanup trap + trap "rm -f tailtestfifo tailout" EXIT + + # create test FIFO + mkfifo tailtestfifo + + ${tail_cmd} -f <tailtestfifo >tailout & + tail_pid=$! + + myintseq 20 >tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + err_exit "test_tail_fifo_1: # tail hung (not expected)" + kill -KILL ${tail_pid} + fi + + wait || err_exit "tail child returned non-zero exit code=$?" + + [[ "$(cat tailout)" == $'11\n12\n13\n14\n15\n16\n17\n18\n19\n20' ]] || err_exit "test_tail_fifo_1: Expected $(doublebackslashquote '11\n12\n13\n14\n15\n16\n17\n18\n19\n20'), got $(doublebackslashquote "$(cat tailout)")" + + return 0 +} + +function test_tail_fifo_2 +{ + typeset tail_cmd="$1" + integer i + integer tail_pid=-1 + + # cleanup trap + trap "rm -f tailtestfifo tailout" EXIT + + # create test FIFO + mkfifo tailtestfifo + + ${tail_cmd} -f tailtestfifo >tailout & + tail_pid=$! + + myintseq 14 >tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14'), got $(doublebackslashquote "$(cat tailout)")" + + myintseq 15 >>tailtestfifo + + waitpidtimeout ${tail_pid} 5 + + if isvalidpid ${tail_pid} ; then + kill -KILL ${tail_pid} + else + err_exit "test_tail_fifo_2: # tail exit with return code $? (not expected)" + fi + fi + + wait || err_exit "tail child returned non-zero exit code=$?" + + [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15'), got $(doublebackslashquote "$(cat tailout)")" + + return 0 +} + +# fixme: This should test /usr/bin/tail and /usr/xpg4/bin/tail in Solaris +test_tail_fifo_1 "tail" +test_tail_fifo_2 "tail" + + +# test 5: "tail -f" tests +function followtest1 +{ + typeset -r FOLLOWFILE="followfile.txt" + typeset -r OUTFILE="outfile.txt" + + typeset title="$1" + typeset testcmd="$2" + typeset usenewline=$3 + typeset followstr="" + typeset newline="" + integer i + integer tailchild=-1 + + if ${usenewline} ; then + newline=$'\n' + fi + + rm -f "${FOLLOWFILE}" "${OUTFILE}" + print -n "${newline}" > "${FOLLOWFILE}" + + ${testcmd} -f "${FOLLOWFILE}" >"${OUTFILE}" & + (( tailchild=$! )) + + for (( i=0 ; i < 10 ; i++)) ; do + followstr+="${newline}${i}" + print -n "${i}${newline}" >>"${FOLLOWFILE}" + sleep 2 + + [[ "$( < "${OUTFILE}")" == "${followstr}" ]] || err_exit "${title}: Expected $(doublebackslashquote "${followstr}"), got "$(doublebackslashquote "$( < "${OUTFILE}")")"" + done + + #kill -TERM ${tailchild} 2>/dev/null + kill -KILL ${tailchild} 2>/dev/null + waitpidtimeout ${tailchild} 5 + + if isvalidpid ${tailchild} ; then + err_exit "${title}: tail pid=${tailchild} hung." + kill -KILL ${tailchild} 2>/dev/null + fi + + wait ${tailchild} 2>/dev/null + + rm -f "${FOLLOWFILE}" "${OUTFILE}" + + return 0 +} + +followtest1 "test5a" "tail" true +# fixme: later we should test this, too: +#followtest1 "test5b" "tail" false +#followtest1 "test5c" "/usr/xpg4/bin/tail" true +#followtest1 "test5d" "/usr/xpg4/bin/tail" false +#followtest1 "test5e" "/usr/bin/tail" true +#followtest1 "test5f" "/usr/bin/tail" false + + +# cleanup +cd "${ocwd}" +rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh b/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh new file mode 100644 index 0000000000..77ab14714e --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_command_substitution.sh @@ -0,0 +1,291 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Written by Roland Mainz <roland.mainz@nrubsig.org> +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} +integer testfilesize i maxwait +typeset tmpfile +integer testid + + +######################################################################## +#### test set 001: +# run loop and check various temp filesizes +# (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh) + +# test 1: run loop and check various temp filesizes +tmpfile="$(mktemp "/tmp/ksh93_tests_command_substitution.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." + +compound test1=( + compound -a testcases=( + # test 1a: Run test child for $(...) + # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) + ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1b: Same as test1a but uses ${... ; } instead if $(...) + ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1c: Same as test1a but does not use a pipe + ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1d: Same as test1a but does not use a pipe + ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + + # test 1e: Same as test1a but uses an external "cat" command + ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1f: Same as test1a but uses an external "cat" command + ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1g: Same as test1a but uses an external "cat" command + ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1h: Same as test1a but uses an external "cat" command + ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + ) +) + +for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do + # Create temp file + { + for (( i=0 ; i < testfilesize ; i+=64 )) ; do + print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" + done + } >"${tmpfile}" + + # wait up to log2(i) seconds for the child to terminate + # (this is 10 seconds for 1KB and 19 seconds for 512KB) + (( maxwait=log2(testfilesize) )) + + for testid in "${!test1.testcases[@]}" ; do + nameref currtst=test1.testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + # compare input/output + cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." + rm "${tmpfile}.out" + done + + # Cleanup + rm "${tmpfile}" +done + + +######################################################################## +#### test set 002: +# If a command substitution calls a function and that function contains +# a command substitution which contains a piped command, the original +# command substitution calling the function will return 127 instead of 0. +# This is causing problems in several VSC tests. +# If we remove the piped command from the simple +# case in the attached script, it returns 0. + +typeset str +typeset testbody +typeset testout + +testbody=$( +# <CS> means command substitution start, <CE> means command substitution end +cat <<EOF +myfunc () +{ + pipedcmd=<CS> printf "hi" | tr "h" "H" <CE> + echo \$pipedcmd + + return 0 +} + +foo=<CS>myfunc<CE> +retval=\$? + +if [ "\$foo"X != "HiX" ]; then + echo "myfunc returned '\${foo}'; expected 'Hi'" +fi + +if [ \$retval -ne 0 ]; then + echo "command substitution calling myfunc returned \"\${retval}\"; expected 0" +else + echo "command substitution calling myfunc successfully returned 0" +fi +EOF +) + + +# Test 002/a: Plain test +testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/b: Same as test002/a but replaces "$(" with "${" +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0" +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/d: Same as test002/a but uses extra subshell +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + +# Test 002/e: Same as test002/b but uses extra subshell after "${ " +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" + + + + +######################################################################## +#### test set 003: +# An expression within backticks which should return false, instead +# returns true (0). + +typeset str +typeset testbody +typeset testout + +testbody=$( +# <CS> means command substitution start, <CE> means command substitution end +cat <<EOF +if <CS>expr "NOMATCH" : ".*Z" > /dev/null<CE> ; then + echo "xerror" +else + echo "xok" +fi +EOF +) + + +# Test 003/a: Plain test +testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/b: Same as test003/a but replaces "$(" with "${" +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0" +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/d: Same as test003/a but uses extra subshell +testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + +# Test 003/e: Same as test003/b but uses extra subshell after "${ " +testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } +[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" + + +######################################################################## +#### test set 004: +# test pipe within ${... ; } command subtitution ending in a +# non-builtin command (therefore we use "/bin/cat" instead of "cat" below +# to force the use of the external "cat" command). ast-ksh.2009-01-20 +# had a bug which caused this test to fail. +testout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' ) +[[ "${testout}" == "hi" ]] || err_exit "test004: Expected 'hi', got '${testout}'" + + +######################################################################## +#### test set 005: +# Test whether the shell may hang in a +# 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)' +# Originally discovered with ast-ksh.2009-05-05 which hung in +# the "configure" script of postgresql-8.3.7.tar.gz (e.g. +# configure --enable-thread-safety --without-readline) +compound test5=( + compound -a testcases=( + # gsf's reduced testcase + ( name="test5_a" cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' ) + # gisburn's reduced testcase + ( name="test5_b" cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' ) + + ## The following tests do not trigger the problem but are included here for completeness + ## and to make sure we don't get other incarnations of the same problem later... + + # same as test5_a but uses ${ ... ; } instead of $(...) + ( name="test5_c" cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' ) + # same as test5_b but uses ${ ... ; } instead of $(...) + ( name="test5_d" cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' ) + # same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) + ( name="test5_e" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' ) + # same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) + ( name="test5_f" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' ) + ) +) + +maxwait=5 +for testid in "${!test5.testcases[@]}" ; do + nameref currtst=test5.testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + testout="$( < "${tmpfile}.out")" + rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed." + [[ "${testout}" == "done" ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh b/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh new file mode 100644 index 0000000000..3714227449 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_compound_nameref.sh @@ -0,0 +1,215 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + + + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# name reference test #001 +# Note we run this test in a seperate shell to make sure the memory +# corruption originally reported can be reproduced (which precisely +# depends on ordering in the testcase) +( +cat <<EOF + function err_exit + { + print -u2 -n "\t" + print -u2 -r \${Command}[\$1]: "\${@:2}" + (( Errors++ )) + } + alias err_exit='err_exit \$LINENO' + + function function2 + { + nameref v=\$1 + + v.x=19 + v.y=20 + } + + function function1 + { + typeset compound_var=() + + function2 compound_var + + printf "x=%d, y=%d\n" compound_var.x compound_var.y + } + + x="\$(function1)" + + [[ "\$x" == 'x=19, y=20' ]] || err_exit "expected 'x=19, y=20', got '\${x}'" + +EOF +) | ${SHELL} +(( Errors+=$? )) + + +# +# name reference test #002 +# Originally derived from the xmldocumenttree1.sh demo which failed +# with ast-ksh.2009-04-15 since the nodepath+nodesnum nameref calls +# were removing the compound variable members nodes+nodesnum (caused +# by a scoping bug) +# +( +cat <<EOF + compound xdoc + compound -A xdoc.nodes + integer xdoc.nodesnum=0 + + function test1 + { + nameref doc=xdoc + nameref nodepath="doc.nodes" + nameref nodesnum="doc.nodesnum" + print -v doc + } + + test1 +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" + +(( ${ wc -l <<<"${out}" ; } == 4 )) || err_exit "Expected four lines of output, got ${out}" +(set -o errexit ; read -C tmp <<<"${out}" ; [[ "$(typeset +p tmp.nodes)" == *-A* ]]) || err_exit "missing variable tmp.nodes" +(set -o errexit ; read -C tmp <<<"${out}" ; [[ -v tmp.nodesnum ]]) || err_exit "missing variable tmp.nodesnum" + + +# +# name reference test #003a +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -A addrsp + + nameref sp=addrsp + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #003b +# (same as test #003a but uses a function) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -A addrsp + + function t1 + { + nameref sp=\$1 + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi + } + + t1 addrsp +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #004a +# (same as #003a but uses an indexed array instead of an associative one) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -a addrsp + + nameref sp=addrsp + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# +# name reference test #004b +# (same as test #004a but uses a function) +# ast-ksh.2009-06-30 failed with the following compound variable/nameref test +# +( +cat <<EOF + compound -a addrsp + + function t1 + { + nameref sp=\$1 + + sp[14]=( size=1 ) + + if [[ -v sp[19] ]] ; then + print "should not happen" + else + print "Ok" + fi + } + + t1 addrsp +EOF +) | out=$( ${SHELL} ) || err_exit "shell returned exit code $?" +[[ "${out}" == "Ok" ]] || err_exit "Expected 'Ok', got ${out}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh b/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh index 18aed2aa7a..52bc5dca82 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_compoundvario.sh @@ -20,20 +20,25 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' -typeset -C bracketstat=( +# "nounset" disabled for now +#set -o nounset +Command=${0##*/} +integer Errors=0 + +compound bracketstat=( integer bopen=0 integer bclose=0 ) @@ -57,7 +62,45 @@ function count_brackets return 0 } -integer Errors=0 +# compound variable "cat" nr.1, using $ print "%B\n" ... # +function cpvcat1 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf "%B\n" tmp ; done + return 0 +} + +# compound variable "cat" nr.2, using $ print "%#B\n" ... # +function cpvcat2 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf "%#B\n" tmp ; done + return 0 +} + +# compound variable "cat" nr.3, using $ print -C ... # +function cpvcat3 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -C tmp ; done + return 0 +} + +# compound variable "cat" nr.4, using $ print -v ... # +function cpvcat4 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -v tmp ; done + return 0 +} typeset s @@ -71,7 +114,7 @@ typeset s # -- snip -- # (additionally we test some extra stuff like bracket count) s=${ - typeset -C x=( + compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) @@ -88,7 +131,7 @@ s=${ integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -96,13 +139,19 @@ s=${ [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) { printf "%B\n" x print "hello" - } | { + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { read -C y read s } @@ -111,6 +160,8 @@ s=${ [[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}" count_brackets "$y" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" # cleanup unset x y || err_exit "unset failed" @@ -128,11 +179,11 @@ unset x y || err_exit "unset failed" # <compound var> # -- snip -- s=${ - typeset -C x=( + compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) - typeset -A myarray3=( + compound -A myarray3=( [a]=( float m1=0.5 float m2=0.6 @@ -145,7 +196,7 @@ s=${ integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -153,6 +204,12 @@ s=${ [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) @@ -160,7 +217,7 @@ s=${ printf "%B\n" x print "hello" printf "%B\n" x - } | { + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { read -C y1 read s read -C y2 @@ -170,10 +227,22 @@ s=${ } || err_exit "test returned exit code $?" [[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}." +[[ "${y1.myarray3[b].foo}" == "bar" ]] || err_exit "y1.myarray3[b].foo != bar" +[[ "${y2.myarray3[b].foo}" == "bar" ]] || err_exit "y2.myarray3[b].foo != bar" [[ "$y1" != "" ]] || err_exit "y1 is empty" [[ "$y2" != "" ]] || err_exit "y2 is empty" +(( ${#y1.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y1.myarray3[e].nested_cpv, got ${#y1.myarray3[e].nested_cpv[@]}" +(( ${#y2.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y2.myarray3[e].nested_cpv, got ${#y2.myarray3[e].nested_cpv[@]}" +(( isnan(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not a NaN" +(( isnan(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not a NaN" +(( signbit(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not negative" +(( signbit(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not negative" count_brackets "$y1" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" count_brackets "$y2" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" [[ "$y1" == "$y2" ]] || err_exit "Expected $(printf "%q\n" "${y1}") == $(printf "%q\n" "${y2}")." [[ "$x" == "$y1" ]] || err_exit "Expected $(printf "%q\n" "${x}") == $(printf "%q\n" "${y}")." @@ -185,11 +254,11 @@ unset x y1 y2 || err_exit "unset failed" # Test 3: Test compound variable copy operator vs. "read -C" -typeset -C x=( +compound x=( a=1 b=2 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) - typeset -A myarray3=( + compound -A myarray3=( [a]=( float m1=0.5 float m2=0.6 @@ -202,7 +271,7 @@ typeset -C x=( integer at=90 ) [e]=( - typeset -C nested_cpv=( + compound nested_cpv=( typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) typeset str=$'a \'string' ) @@ -210,27 +279,41 @@ typeset -C x=( [f]=( typeset g="f" ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) ) ) -typeset -C x_copy=x || err_exit "x_copy copy failed" +compound x_copy=x || err_exit "x_copy copy failed" [[ "${x_copy}" != "" ]] || err_exit "x_copy should not be empty" count_brackets "${x_copy}" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" -typeset -C nested_cpv_copy +compound nested_cpv_copy nested_cpv_copy=x.myarray3[e].nested_cpv || err_exit "x.myarray3[e].nested_cpv copy failed" +(( ${#nested_cpv_copy.myarray[@]} == 10 )) || err_exit "Expected 10 elements in nested_cpv_copy.myarray, got ${#nested_cpv_copy.myarray[@]}" # unset branch "x.myarray3[e].nested_cpv" of the variable tree "x" ... unset x.myarray3[e].nested_cpv || err_exit "unset x.myarray3[e].nested_cpv failed" [[ "${x.myarray3[e].nested_cpv}" == "" ]] || err_exit "x.myarray3[e].nested_cpv still has a value" # ... and restore it from the saved copy -printf "%B\n" nested_cpv_copy | read -C x.myarray3[e].nested_cpv || err_exit "read failed" +printf "%B\n" nested_cpv_copy | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | read -C x.myarray3[e].nested_cpv || err_exit "read failed" # compare copy of the original tree and the modified one [[ "${x}" == "${x_copy}" ]] || err_exit "x != x_copy" count_brackets "${x}" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +(( ${#x.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in x.myarray3[e].nested_cpv, got ${#x.myarray3[e].nested_cpv[@]}" +(( isnan(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not a NaN" +(( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative" # cleanup unset x x_copy nested_cpv_copy || err_exit "unset failed" @@ -238,14 +321,15 @@ unset x x_copy nested_cpv_copy || err_exit "unset failed" # Test 4: Test "read -C" failure for missing bracket at the end typeset s -s=$($SHELL -c 'typeset -C myvar ; print "( unfinished=1" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" +s=$($SHELL -c 'compound myvar ; print "( unfinished=1" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" [[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}" # Test 5: Test "read -C" failure for missing bracket at the beginning typeset s -s=$($SHELL -c 'typeset -C myvar ; print " unfinished=1 )" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" +s=$($SHELL -c 'compound myvar ; print " unfinished=1 )" | read -C myvar 2>/dev/null || print "error $?"') || err_exit "shell failed" [[ "$s" == "error 3" ]] || err_exit "compound_read: expected error 3, got ${s}" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh index 335470aa79..27cac4aa88 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6687139_command_substitution_exec_redirection_allocation_loop.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -46,6 +46,7 @@ # -- snip -- # +# test setup function err_exit { print -u2 -n "\t" @@ -54,15 +55,16 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} +integer Errors=0 + function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } -Command=${0##*/} -integer Errors=0 - integer childpid typeset testdir integer childretval @@ -208,5 +210,6 @@ childretval=$? cd /tmp rmdir "${testdir}" || err_exit "Could not remove temporary test directory ${testdir}" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh index 4f03984951..28a84caff1 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6713682_compound_var_bleeds_through_subshell.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -51,17 +51,20 @@ # ... provides the correct output. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset var1 var2 # use unset, l=() compound syntax and print @@ -75,13 +78,13 @@ var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l' [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and print -var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and print -var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # use unset, l=() compound syntax and printf "%B\n" @@ -95,14 +98,15 @@ var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l) ; print [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and printf "%B\n" -var1="$(${SHELL} -c 'unset l ; ( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and printf "%B\n" -var1="$(${SHELL} -c '( typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." -var2="$(${SHELL} -c '( ulimit -c 0 ; typeset -C l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." +var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh index 333f5cc1a0..793d53d20d 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6722134_background_CHLD_trap.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -40,17 +40,20 @@ # -- snip -- # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + ## ## test one: ## @@ -115,5 +118,6 @@ print "done" (( count=$(fgrep "got_child" <<< "$s" | wc -l) )) || err_exit "counting failed." (( count == 3 )) || err_exit "Expected count==3, got count==${count}." + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh index c755f86c87..fa016f4c67 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6753538_subshell_leaks_umask.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -40,17 +40,20 @@ # -- snip -- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + # # test set 1: Simple umask in subshell # @@ -93,5 +96,6 @@ x=$(${SHELL} -c 'umask 0; ( umask 20); umask') || err_exit "shell y=$(${SHELL} -c 'umask 0; (ulimit -c 0 ; umask 20); umask') || err_exit "shell failed." [[ "$x" == "$y" ]] || err_exit "$x != $y" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh index d4bd345833..6b0092d5ba 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6754020_weird_square_bracket_expansion.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -45,17 +45,20 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset s # test using "echo" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh index f3ffae5e84..bc3426f063 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6763594_command_failure_execs_twice.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -63,17 +63,20 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + typeset testtmpdir=/tmp/ksh93_test_cr_6763594_${PPID}_$$ mkdir "${testtmpdir}" || { err_exit "Could not create temporary directory ${testtmpdir}." ; exit ${Errors} ; } @@ -90,6 +93,7 @@ s=$( < out_stderr ) ; [[ "$s" == ~(Elr)(.*:\ \./myfoo:\ \./myfoo:\ .*\[.*\]) ]] rm "myfoo" "out_stdout" "out_stderr" || err_exit "rm failed." cd .. rmdir "${testtmpdir}" || err_exit "Failed to remove temporary directory ${testtmpdir}." - + + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh index fc83db0e8a..7463baea5a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6766246_pattern_matching_bug.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -70,15 +70,17 @@ # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 @@ -168,5 +170,6 @@ while (( $# >= 13 )) ; do done done + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh new file mode 100644 index 0000000000..7f76862bdd --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6769332_substitutions_terminate_shell_after_257_iterations.sh @@ -0,0 +1,124 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 supports more than 256 recursive +# function+command substitution calls. +# +# This was reported as CR #6769332 ('Recursive function+command +# substitutions terminate shell after 257 iterations'): +# ------------ snip ------------ +# Recursive function+command substitutions +# (e.g. func1() { x=$( func2 ) ; } ; x=$( func1 ) ) terminate the +# ksh93 shell after 257 iterations with a exit code of "0" (it +# seems the shell just "quits" after the last "return 0" statement +# in the function). +# Running the attached testcase terminates the shell after 257 +# iterations (g=257 in the script) while 256 iterations (replace +# "257" with "256" in the script) just works fine. +# The same testcase works Ok in ksh88 (=/usr/bin/ksh in +# Solaris 10U5) +# +# Expected Result +# The script should output "done" and return the exit code 0. +# +# Actual Result +# No messsge. Exit code "0". +# +# Error Message(s) +# None (exit code is "0"). +# +# Test Case +# f1() +# { +# h=$1 +# (( h=h-1 )) +# (( h <= 0 )) && return 0 +# x=$(f1 "$h" "$l" "$g" d e "$l") || print -u2 "$g/$h: fail" +# return 0 +# } +# l="" +# g=257 +# i=0 +# while (( i < $g )) ; do +# l="${l}x" +# (( i=i+1 )) +# done +# f1 "$g" "$l" "$g" d e "$l" || print -u2 "$g: fail0" +# print "done" +# exit 0 +# +# Workaround +# - +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# test1: Testcase from CR #6769332 +# +( +cat <<EOF +# make sure we have enougth stack (needed for 64bit SPARC and SystemZ) +ulimit -s 65536 + +f1() +{ + h=\$1 + (( h=h-1 )) + (( h <= 0 )) && return 0 + x=\$(f1 "\$h" "\$l" "\$g" d e "\$l") || print -u2 "\$g/\$h: fail" + return 0 +} +l="" +g=257 +i=0 +while (( i < \$g )) ; do + l="\${l}x" + (( i=i+1 )) +done +f1 "\$g" "\$l" "\$g" d e "\$l" || print -u2 "\$g: fail0" +print "done" +EOF +) | out="$( ${SHELL} 2>&1 ; )" || err_exit "Shell returned non-zero exit code $?." + +[[ "${out}" == "done" ]] || err_exit "Output expected to be 'done', got '${out}'." + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh new file mode 100644 index 0000000000..2dd0fc997f --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6777491_lacks_arithmetric_function_iszero.sh @@ -0,0 +1,95 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether the arithmetric function "iszero" is available. +# +# This was reported as CR #6777491 ("*ksh93* lacks arithmetric function +# iszero()"): +# ------------ snip ------------ +# ksh93 lacks arithmetric function "iszero()" which limits the ability +# to classify floating-point values or even correctly match against +# zero (since IEEE754-1985/2008 floating-point math differs between +# positive and negaive zero values). +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# $ ksh93 -c '(( iszero(0) )) && print "0 is a zero"' +# Expected Result +# Output to stdout: +# -- snip -- +# 0 is a zero +# -- snip -- +# Actual Result +# ksh93 exists with: +# -- snip -- +# ksh93: iszero(0) : unknown function +# -- snip -- +# Error Message(s) +# ksh93: iszero(0) : unknown function +# Test Case +# ksh93 -c '(( iszero(0) )) && print "0 is a zero"' +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset str +integer i + +typeset -a tests=( + '(( iszero(0) )) && print "OK"' + '(( iszero(0.) )) && print "OK"' + '(( iszero(-0) )) && print "OK"' + '(( iszero(-0.) )) && print "OK"' + 'float n=0. ; (( iszero(n) )) && print "OK"' + 'float n=+0. ; (( iszero(n) )) && print "OK"' + 'float n=-0. ; (( iszero(n) )) && print "OK"' + 'float n=1. ; (( iszero(n) )) || print "OK"' + 'float n=1. ; (( iszero(n-1.) )) && print "OK"' + 'float n=-1. ; (( iszero(n+1.) )) && print "OK"' +) + +for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + str="$( $SHELL -o errexit -c "${tests[i]}" 2>&1 )" || err_exit "test $i: returned non-zero exit code $?" + [[ "${str}" == "OK" ]] || err_exit "test $i: expected 'OK', got '${str}'" +done + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh new file mode 100644 index 0000000000..24f99cb581 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6778077_sigthaw_trap.sh @@ -0,0 +1,83 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 supports traps for the SIGTHAW +# signal. +# +# This was reported as CR #6778077 ("*ksh93* does not understand "THAW" +# as a signal for use with trap"): +# -- snip -- +# While ksh93 understand THAW in the list of signals for kill it does +# not understand it for "trap' +# +# : pod5.eu TS 6 $; kill -l | egrep '(THAW|FREEZE)' +# FREEZE +# THAW +# : pod5.eu TS 7 $; trap "echo THAW" THAW +# ksh93: trap: THAW: bad trap +# : pod5.eu TS 8 $; +# +# Using the signal number (35) works around this. +# -- snip -- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +## test one: Check whether the shell supports SIGTHAW as trap +${SHELL} -o errexit -c 'trap "true" SIGTHAW ; true' || err_exit "SIGTHAW not supported." +${SHELL} -o errexit -c 'trap "true" THAW ; true' || err_exit "THAW not supported." +${SHELL} -o errexit -c 'trap "true" 35 ; true' || err_exit "signal 35 not supported." + + +## test two: Check whether the shell supports SIGFREEZE as trap +## (we check this since it is SIGTHAW's counterpart) +${SHELL} -o errexit -c 'trap "true" SIGFREEZE ; true' || err_exit "SIGFREEZE not supported." +${SHELL} -o errexit -c 'trap "true" FREEZE ; true' || err_exit "FREEZE not supported." +${SHELL} -o errexit -c 'trap "true" 34 ; true' || err_exit "signal 34 not supported." + + +## test three: Check all other signals listed by "kill -l" +kill -l | while read i ; do + str="$( ${SHELL} -c "trap true $i ; print 'ok'" 2>&1 )" || err_exit "shell returned code $? for trap $i" + [[ "${str}" == "ok" ]] || err_exit "expected 'ok', got $str" +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh new file mode 100644 index 0000000000..69159a9f76 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6789247_printf_hexfloat_rounding.sh @@ -0,0 +1,130 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly supports +# negative zero values +# +# This was reported as CR #6789247 ("libast/ksh93 1-digit hexfloat base conversion rounds incorrectly"): +# ---- snip ---- +# Description +# [The same issue was described in http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2008-December/006737.html] +# This is basically a spin-off of http://bugs.opensolaris.org/view_bug.do?bug_id=6773712 ("1-digit hex fp +# base conversion of long double rounds incorrectly"). +# The bug description for Solaris libc says this: +# > The first line of output from this program is correct. The second line +# > is not. +# > +# > leviathan% cat a.c +# > #include <stdio.h> +# > +# > int main() +# > { +# > printf("%.0a\n", 1.5); +# > printf("%.0La\n", 1.5L); +# > return 0; +# > } +# > leviathan% cc -o a a.c +# > leviathan% a +# > 0x1p+1 +# > 0x1p+0 +# > leviathan% +# If I compile the testcase with libast on Solaris 11/B84 SPARC (which +# matches ast-open.2008-11-04) I get this: +# -- snip -- +# $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && +# ./a +# 0x1p+00 +# 0x1p+00 +# -- snip -- +# ... which seems to be incorrect per the bugs comment above and should +# be: +# -- snip -- +# 0x1p+1 +# 0x1p+1 +# -- snip -- +# ksh93 has the same problem: +# $ ksh93 -c 'float r=1.5 ; printf "%.0a\n" r' +# 0x1p+00 +# Steps to Reproduce +# Compile and run testcase like this: +# -- snip -- +# $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && +# ./a +# -- snip -- +# Expected Result +# 0x1p+1 +# 0x1p+1 +# Actual Result +# 0x1p+00 +# 0x1p+00 +# ---- snip ---- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +float r +float result +typeset str + +# Test #001/a - check whether the result of a rounded 1.5 is 2.0 +r=1.5 +result=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" +(( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" + + +# Test #001/b - same as test #001/a but uses "%.0A\n" instead of "%.0a\n" +r=1.5 +result=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" +(( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" + + +# Test #002/a - check whether the hexfloat string value matches the expected pattern +r=1.5 +str=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" +[[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" + + +# Test #002/b - same as test #002/a but uses "%.0A\n" instead of "%.0a\n" +r=1.5 +str=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" +[[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh index 396095ee63..de745b8a3a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6800929_large_command_substitution_hang.sh @@ -35,7 +35,8 @@ # # and here's where it's hung: # ---8<--- -# xxxxx@xxxxx $ pstack 204600 +# Edward Pilatowicz <edward.pilatowicz@sun.com> +# $ pstack 204600 # 204600: /bin/ksh /opt/onbld/bin/Install -o debug -k i86xpv -T domu-219:/tmp # fffffd7fff2e3d1a write (1, 4154c0, 64) # fffffd7ffefdafc8 sfwr () + 2d0 @@ -70,68 +71,142 @@ # # as it turns out, i can easily reproduce this problem as follows: # ---8<--- -# xxxxx@xxxxx $ ksh93 -# xxxxx@xxxxx $ set -- `cat /etc/termcap | sort | uniq` +# $ ksh93 +# $ set -- `cat /etc/termcap | sort | uniq` # <hang> # ---8<--- # ---- snip ---- +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 -integer i j d +# common functions/variables +function isvalidpid +{ + kill -0 ${1} 2>/dev/null && return 0 + return 1 +} +integer testfilesize i maxwait typeset tmpfile +integer testid + # test 1: run loop and check various temp filesizes tmpfile="$(mktemp "/tmp/sun_solaris_cr_6800929_large_command_substitution_hang.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." -for (( i=1*1024 ; i <= 512*1024 ; i*=2 )) ; do +compound -a testcases=( + # test 1a: Run test child for $(...) + # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) + ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1b: Same as test1a but uses ${... ; } instead if $(...) + ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1c: Same as test1a but does not use a pipe + ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1d: Same as test1a but does not use a pipe + ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) + + # test 1e: Same as test1a but uses an external "cat" command + ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) + # test 1f: Same as test1a but uses an external "cat" command + ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) + # test 1g: Same as test1a but uses an external "cat" command + ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) + # test 1h: Same as test1a but uses an external "cat" command + ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) +) + +for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do # Create temp file { - for ((j=0 ; j < i ; j+=16 )) ; do - print "0123456789abcde" + for (( i=0 ; i < testfilesize ; i+=64 )) ; do + print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" done } >"${tmpfile}" - - # Run test child - ${SHELL} -c "builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" >/dev/null & - (( childpid=$! )) # wait up to log2(i) seconds for the child to terminate # (this is 10 seconds for 1KB and 19 seconds for 512KB) - (( d=log2(i) )) - for (( j=0 ; j < d ; j++ )) ; do - kill -0 ${childpid} 2>/dev/null || break - sleep 0.5 + (( maxwait=log2(testfilesize) )) + + for testid in "${!testcases[@]}" ; do + nameref currtst=testcases[testid] + ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & + (( childpid=$! )) + + for (( i=0 ; i < maxwait ; i++ )) ; do + isvalidpid ${childpid} || break + sleep 0.25 + done + + if isvalidpid ${childpid} ; then + err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." + kill -KILL ${childpid} 2>/dev/null + fi + wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + # compare input/output + cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." + rm "${tmpfile}.out" done - if kill -0 ${childpid} 2>/dev/null ; then - err_exit "test1: child (pid=${childpid}) still busy, filesize=${i}." - kill -KILL ${childpid} 2>/dev/null - fi - wait # wait for child (and/or avoid zombies/slime) + # Cleanup rm "${tmpfile}" done -# test 2: Edward's Solaris-specific testcase -${SHELL} -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & +# test 2a: Edward Pilatowicz <edward.pilatowicz@sun.com>'s Solaris-specific testcase +${SHELL} -o errexit -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & (( childpid=$! )) sleep 5 -if kill -0 ${childpid} 2>/dev/null ; then - err_exit "test2: child (pid=${childpid}) still busy." +if isvalidpid ${childpid} ; then + err_exit "test2a: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi -wait # wait for child (and/or avoid zombies/slime) +wait || err_exit "test2a: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2b: Same as test 2a but uses ${... ; } instead of $(...) +${SHELL} -o errexit -c 'builtin uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2b: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2b: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2c: Same as test 2a but makes sure that "uniq" is not a builtin +${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2c: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2c: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + + +# test 2d: Same as test 2c but uses ${... ; } instead of $(...) +${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & +(( childpid=$! )) +sleep 5 +if isvalidpid ${childpid} ; then + err_exit "test2d: child (pid=${childpid}) still busy." + kill -KILL ${childpid} 2>/dev/null +fi +wait || err_exit "test2d: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh new file mode 100644 index 0000000000..4f774b2f8b --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805792_varmovetest1.sh @@ -0,0 +1,152 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether "typeset -m" correctly moves local variables +# into a global variable tree. +# +# This was reported as CR #6805792 ("XXXX"): +# -------- snip -------- +# The following attempt to move a local node into an associative array +# fails like this: +# -- snip -- +# typeset -C tree +# function f1 +# { +# nameref tr=$1 +# +# typeset -A tr.subtree +# +# typeset -C node +# +# node.one="hello" +# node.two="world" +# +# # move local note into the array +# typeset -m tr.subtree["a_node"]=node +# +# return 0 +# } +# f1 tree +# printf "%B\n" tree +# print "ok" +# exit 0 +# -- snip -- +# The output looks like this: +# -- snip -- +# $ ksh93 +# varmovetest1.sh +# ( +# ( +# ) +# ok +# -- snip -- +# ... but AFAIK it should print: +# -- snip -- +# ( +# typeset -A subtree=( +# [a_node]=( +# one=hello +# two=world +# ) +# ) +# ) +# ok +# -- snip -- +# -------- snip -------- +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +## test start +compound tree1 tree2 + +# add node to tree which uses "typeset -m" to move a local variable +# into tree1.subtree["a_node"] +function f1 +{ + nameref tr=$1 + + typeset -A tr.subtree + + compound node + + node.one="dummy1" + node.two="dummy2" + + # We use the nameref's here since ast-ksh,2008-12-12 crashes + # when this function returns because "nodeone" and "nodetwo" + # still reference "node" which was renamed. + # (note that "f1" must be first function and the first being + # called, otherwise the crash will not occur) + nameref nodeone=node.one + nameref nodetwo=node.two + nodeone="hello" + nodetwo="world" + + # move local note into the array + typeset -m tr.subtree["a_node"]=node + + return 0 +} + +# Alternative version which uses "nameref" instead of "typeset -m" +function f2 +{ + nameref tr=$1 + + typeset -A tr.subtree + + nameref node=tr.subtree["a_node"] + + node.one="hello" + node.two="world" + + return 0 +} + +f1 tree1 +f2 tree2 + +[[ "${tree1.subtree["a_node"].one}" == "hello" ]] || err_exit "Expected tree1.subtree[\"a_node\"].one == 'hello', got ${tree1.subtree["a_node"].one}" +[[ "${tree1.subtree["a_node"].two}" == "world" ]] || err_exit "Expected tree1.subtree[\"a_node\"].two == 'world', got ${tree1.subtree["a_node"].two}" +[[ "${tree1}" == "${tree2}" ]] || err_exit "tree1 and tree2 differ:"$'\n'"$(diff -u <( printf '%B\n' tree1 ) <( printf '%B\n' tree2 ) )" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh new file mode 100644 index 0000000000..bbcb9b168d --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805794_character_to_wchar_not_working.sh @@ -0,0 +1,106 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric operator '<character> +# is working +# +# This was reported as CR #6805794 ('[ku1] printf returns "invalid character constant" for $ printf "%d\n" "'<euro>"'): +# ------------ snip ------------ +# There seems be a bug in how ast-ksh.2008-11-04's "printf" builtin +# handles multibyte characters. For example if I try this in the +# en_US.UTF-8 locale ("<euro>" needs to be replace with the EURO symbol): +# -- snip -- +# $ printf "%d\n" "'<euro>" +# -ksh93: printf: warning: ': invalid character constant +# 226 +# -- snip -- +# AFAIK the correct behaviour was to return the numeric value of the +# <euro> symbol in this case (hexadecimal "20ac", decimal 8364), e.g. +# -- snip -- +# $ printf "%d\n" +# "'<euro>" +# 8364 +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# Enter this in an interractive shell: +# $ printf "%d\n" "'<euro>" +# Expected Result +# -- snip -- +# $ printf "%d\n" +# "'<euro>" +# 8364 +# -- snip -- +# Actual Result +# -- snip -- +# $ printf "%d\n" "'<euro>" +# -ksh93: printf: warning: ': invalid character constant +# 226 +# -- snip -- +# Error Message(s) +# printf: warning: ': invalid character constant +# Test Case +# printf "%d\n" "'<euro>" +# Workaround +# None. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# declare variables +typeset str + +# test whether the locale uses an UTF-8 (-like) encoding and override it on demand +[[ "$(printf "\u[20ac]")" == $'\342\202\254' ]] || LC_ALL=en_US.UTF-8 +if [[ "$(printf "\u[20ac]")" != $'\342\202\254' ]] ; then + err_exit "Local overrride failed." + exit $((Errors)) +fi + +# run test +str=$(print $'printf "%d\\\\n" "\'\342\202\254"' | source /dev/stdin) +[[ "${str}" == "8364" ]] || err_exit "expected 8364, got ${str}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh new file mode 100644 index 0000000000..1dccc97505 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6805795_negative_zero.sh @@ -0,0 +1,170 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly supports +# negative zero values +# +# This was reported as CR #6805795 ("[ku1] ksh93 does not differ between -0 and +0"): +# ------------ snip ------------ +# Original bug report was: +# ------ snip ------ +# Is there a reason why ksh93 does not display the negative sign for the +# value zero ? For example if I have use the C99 function "copysign" +# (copies absolute value of operant a and sign of operant b) I get this +# for { a=5, b=-0 }: +# -- snip -- +# $ ksh93 -c 'float x; (( x=copysign(5, -0) )) ; printf "%f\n" +# x' +# -5.000000 +# -- snip -- +# Now if I swap operands a and b I get this result: +# -- snip -- +# $ ksh93 -c 'float x; (( x=copysign(0, -5) )) ; printf "%f\n" x' +# 0.000000 +# -- snip -- +# AFAIK this result should be "-0.000000" ... or not ? +# BTW: Parsing of "-0" doesn't seem to work either, e.g. +# -- snip -- +# $ ksh93 -c 'float x a=-1 b=-0; (( x=copysign(a, b) )) ; printf "%f\n" +# x' +# 1.000000 +# -- snip -- +# ... while AFAIK it should be "-1.000000" since the 2nd operand of +# "copysign" defines the sign of the result. +# ------ snip ------ +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset str + +# test 1: test "copysign()" using constant values +str=$( + set -o errexit + + print -- $(( copysign(0, -5) )) + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected copysign(0, -5) == -0, got ${str}" + + +# test 2: Same as test 1 but using variables for the values +str=$( + set -o errexit + + float a + float b + float c + + a=0. + b=-5. + + (( c=copysign(a, b) )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" + + +# test 3: test "signbit()" +str=$( + set -o errexit + + float a + + a=-0. + + print -- $(( signbit(a) )) + ) || err_exit "test failed." +[[ "${str}" == "1" ]] || err_exit "Expected signbit(a, b) == 1, got ${str}" + + +# test 4: test "signbit()" +str=$( + set -o errexit + + float a + float c + + a=-0. + + (( c=signbit(a) )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "1" ]] || err_exit "Expected c == 1, got ${str}" + + +# test 5: test whether "typeset -X" (C99 "hexfloat") correctly recognizes +# negative zero assigned from a "float" +str=$( + set -o errexit + + float a # float + typeset -X c # hexfloat + + a=-0. + + # copy value from "float" to "hexfloat" + (( c=a )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == -0x* ]] || err_exit "Expected c == -0x*, got ${str}" + + +# test 6: Reverse of test 5: Test whether "float" correctly recognizes +# a C99 "hexfloat" value +str=$( + set -o errexit + + typeset -X a # hexfloat + float c # float + + a=-0x0.0000000000000000000000000000p+00 + + # copy value from "hexfloat" to "float" + (( c=a )) + + print -- "$c" + ) || err_exit "test failed." +[[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh new file mode 100644 index 0000000000..dc91bbeb82 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6835835_builtin_cat_n_broken.sh @@ -0,0 +1,139 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93's builtin "cat" command properly +# supports the "-n" option. +# +# This was reported as CR #6835835 ('ksh93 "cat" builtin does not handle "-n" correctly'): +# ------------ snip ------------ +# [Originally reported in +# http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html +# by Casper Dik] +# -- snip -- +# I just noticed this in ksh93: +# ksh93 -c 'yes "" | head -5|cat -n' +# 1 +# 2 +# 3 +# 4 +# (I used this for older shells when I want to a list of all integers from 1 +# to a particular number) +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# Execute $ ksh93 -c 'yes "" | head -5|cat -n' # +# Expected Result +# 1 +# 2 +# 3 +# 4 +# 5 +# Actual Result +# +# +# 1 +# 2 +# +# 3 +# +# 4 +# Error Message(s) +# None. +# Test Case +# See description. +# Workaround +# Disable ksh93's builtin "cat" command either via using an absolute path +# to the "cat" command (POSIX-style workaround) or using ksh93's +# "builtin" command to remove "cat" from the list of builtin +# commands (e.g. $ builtin -d /bin/cat /usr/bin/cat #). +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +# +# test 1: Compare output of various "cat -n" combinations +# +integer i +typeset expected_output +typeset out + +expected_output=$( ${SHELL} -c 'for ((i=1 ; i <= 12 ; i++ )) ; do printf "%6d\t\n" i ; done' ) + +compound -a testcases=( + # note: we have to add an extra /usr/bin/cat at the end of the pipe to make + # sure the "cat" builtin uses the correct buffering mode to trigger + # the error and a "true" to make sure the "cat" command isn't the last command + # of the shell + ( name="test1a" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n | /usr/bin/cat ; true' ) + # same as "test1a" but uses external "cat" command + ( name="test1b" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /usr/bin/cat -n | /usr/bin/cat ; true' ) + + # same as "test1a" but without the last /usr/bin/cat in the pipe + ( name="test1c" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n ; true' ) + # same as "test1b" but without the last /usr/bin/cat in the pipe + ( name="test1d" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /usr/bin/cat -n ; true' ) +) + +for testid in "${!testcases[@]}" ; do + nameref tc=testcases[${testid}] + + out="$( ${SHELL} -o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" + [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" + + out="$( ${SHELL} +o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" + [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" +done + + +# +# test 2: Casper Dik's original testcase +# from http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html +# + +cmp -s \ + <( ${SHELL} -c 'yes "" | head -5 | cat -n' ) \ + <( for ((i=1 ; i <= 5 ; i++ )) ; do printf "%6d\t\n" i ; done ) \ + || err_exit 'yes "" | head -5 | cat -n does not match expected output.' + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh new file mode 100644 index 0000000000..396816960a --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6848486_echo_test_with_test_undefined_executes_test_builtin.sh @@ -0,0 +1,94 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether ksh93 does not execute builtin command +# "foo" when referencing variable "foo" when the variable is not +# set (this applies to all builtin commands not bound to a +# specific PATH element, e.g. "test", "sleep", "print" etc.). +# +# This was reported as CR #6848486 ('"echo ${test}" with test +# undefined crashes the shell') +# ------------ snip ------------ +# This is an odd one: +# +# $ ksh93 --version +# version sh (AT&T Research) 93t 2008-11-04 +# $ ksh93 +# jl138328@gir:~$ echo $test +# +# jl138328@gir:~$ echo ${test} +# Segmentation Fault (core dumped) +# ------------ snip ------------ +# +# The bug originates from the ksh93 "type system" which allows +# an application to define it's own types in ksh93. In such cases +# the output of function "mytype.len" is used when type "mytype" +# has no member variable "len" (note it requires the use of +# ${foo} since the use of $foo does not allow "foo" to contain +# a dot in the variable name). +# The implementation in ast-ksh.2009-11-04 however does this +# for _all_ types of variables and not only for those which +# are a member of an application-defined type, therefore +# causing this bug. +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# Test 1: Test whether the shell crashes when looking for an empty +# "shell" variable. +# (note: return code 78 was just picked randomly) +$SHELL -c 'unset test ; print ${test} ; exit 78' >/dev/null 2>&1 +(( $? == 78 )) || err_exit "expected return code is 78, got $?" + + +# Test 2: Test whether the shell can reach a point (which prints +# "#mark") after the use of ${test} in the script. +out=$($SHELL -o errexit -c 'unset test ; print ${test} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." +[[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" + + +# Test 3: Check whether the use of ${sleep} returns nothing +# (ast-ksh.2008-11-04 will return the usage string of the sleep +# builtin) +out=$($SHELL -o errexit -c 'print ${sleep} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." +[[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh new file mode 100644 index 0000000000..22de05b56c --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6855875_typeset_hexfloat_has_too_few_digits.sh @@ -0,0 +1,145 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether arithmetric math correctly +# converts a IEEE 754-2008 floating-point value to the C99 hexfloat format +# and back _without_ using digits. +# +# This was reported as CR #6855875 ("typeset -X x ; print $x # does not +# print sufficient digits to restore value"): +# ------------ snip ------------ +# $ typeset -X varname # was added to ksh93 to get a reliable way +# (using the C99 "hexfloat" format (see printf(3c)'s "%a" format)) to +# serialise a IEEE754-2008 floating-point value to a string and later feed +# it back into a application _without_ loosing any precision (normal +# base10 floating-point values (e.g. used by $ typeset -E/-F-G #) cause +# rounding errors since IEEE754-2008 |long double| uses base2). +# However $ typeset -l -X x ; ... ; print $x # currently does not print +# sufficient number of digits to restore the full |long double| value as +# expected, instead some digits are missing, resulting in an unwanted +# rounding. +# Example: +# -- snip -- +# $ ksh93 -c 'typeset -l -X y y_ascii; (( y=sin(90) )) ; y_ascii=$y ; (( y +# == y_ascii )) || print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf +# "%a\n" y_ascii)"' +# no match, +# 0x1.c9b9ee41cb8665c7890a136ace6bp-01 +# != +# 0x1.c9b9ee41cc000000000000000000p-01 +# -- snip -- +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# [See description] +# Expected Result +# [See description] +# Actual Result +# [See description] +# Error Message(s) +# - +# Test Case +# typeset -l -X y y_ascii +# (( y=sin(90) )) +# y_ascii=$y # convert y to string and store it in "y_ascii" +# if (( y == y_ascii )) ; then +# print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" +# y_ascii)" +# fi +# Workaround +# 1. Manually increase the number of digits via typeset +# -X<numdigits> +# OR +# 2. Use $ printf "%a" varname # +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + +# declare variables +typeset str +integer i +float x +float -a test_values + +typeset -l -X y # hexfloat +typeset -l -E y_restored1 +typeset -l -F y_restored2 +typeset -l -X y_restored3 + + +# create array of test values +for (( x=-181. ; x < 361. ; x+=.1 )) ; do + test_values+=( x ) +done +test_values+=( 0 -0 +0 ) # (nan -nan inf -inf) are excluded since nan!=nan is always "true" + + +# run the tests +for (( i=0 ; i < ${#test_values[@]} ; i++ )) ; do + (( y=sin(test_values[i]) )) + + # convert floating-point value to string (using the hexfloat format) and store it in "str" + str="${y}" + + # convert it back (via string assignment) + y_restored1="${str}" + y_restored2="${str}" + y_restored3="${str}" + (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" + (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" + (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" + + # convert it back (using arithmetric expression) + (( y_restored1=str )) + (( y_restored2=str )) + (( y_restored3=str )) + (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" + (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" + (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" + + # we exit if we get more than 8 errors (126 would be the maximum) + (( Errors > 8 )) && exit $((Errors)) +done + + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh new file mode 100644 index 0000000000..568b43f35d --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.sh @@ -0,0 +1,111 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether the Solaris kernel can directly execute compiled +# shell code. +# +# This was reported as CR #6862121 ("shbinexec kernel module defunct"): +# ------------ snip ------------ +# [Originally reported by Sun Japan] +# The new shbinexec kernel module added in B106 is defunct, originally +# caused by my mismerge of the original development tree and later +# because the matching test module didn't test it correctly (April +# quickly discovered the problem but the issue drowned in the cleanup +# putbacks ). +# Frequency +# Always +# Regression +# No +# Steps to Reproduce +# $ cat test1.sh +# print hello +# printf "args=%s\n" "$@" +# $ shcomp test1.sh test1 +# # note: this MUST be bash since ksh93 has special support for compiled shell +# # scripts which causes the kernel module to be bypassed (that's why the tes +# # never worked) +# $ bash -c './test1 "a b" "c" "d"' +# Expected Result +# hello +# args=a a1 +# args=b +# args=c +# Actual Result +# ./test1: line 1: a: not found +# Error Message(s) +# ./test1: line 1: a: not found +# Test Case +# See above. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +typeset ocwd +typeset tmpdir +typeset out + +# create temporary test directory +ocwd="$PWD" +tmpdir="$(mktemp -d "test_sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.XXXXXXXX")" || err_exit "Cannot create temporary directory" + +cd "${tmpdir}" || err_exit "cd ${tmpdir} failed." + + +# run tests +{ +cat <<EOF + print hello + printf "args=%s\n" "\$@" +EOF +} >script1.sh + +# Compile script (note we use the platform's /usr/bin/shcomp, _not_ ${SHCOMP}) +/usr/bin/shcomp "script1.sh" "script1" || err_exit "shcomp failed with error=$?" + +[[ -x "./script1" ]] || err_exit "Script script1 not executable" +out="$(/usr/bin/bash -c './script1 a b "c d"' 2>&1 )" || err_exit "Compiled script failed to execute, error=$?" +[[ "${out}" == $'hello\nargs=a\nargs=b\nargs=c d' ]] || err_exit "Expected xxx, got $(printf "%q\n" "$out")" + +# cleanup +rm "script1" "script1.sh" +cd "${ocwd}" +rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh new file mode 100644 index 0000000000..a5aae41ce5 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/sun_solaris_cr_6881017_background_process_in_subshell_hangs_caller.sh @@ -0,0 +1,82 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether a background process called in a subshell can +# cause it to wait for the child process instead of exiting. +# +# This was reported as CR #6881017 ("Subshell doesn't exit, holds pipe +# open preventing callers from exiting"): +# ------------ snip ------------ +# The following scenario hangs with snv_122, 100% reproducible: +# +# Create a script hangit: +# ----- +# #!/bin/ksh +# ( sleep 100000 </dev/null >/dev/null 2>&1 & ) +# exit 0 +# ----- +# +# Run the following command: +# hangit | tee -a /tmp/log +# +# The hang can be eliminated either by removing the "exit 0" line (?!?), or by +# redirecting the subshell output to /dev/null. +# +# This is pretty nasty. I've whittled it down to this simple case but am seeing +# it in a much more subtle and complex environment where there are several +# intermediate calling scripts which have exited and eventually the parent pipes +# the output and hangs on the open pipe. It was hard to track down. +# ------------ snip ------------ +# + +# test setup +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +float tstart tstop tdiff + +# run test with 10 second timeout +(( tstart=SECONDS )) +$SHELL -c '( sleep 10 </dev/null >/dev/null 2>&1 & ) ; exit 0' | cat >/dev/null +(( tstop=SECONDS )) + +# we remove two seconds below to make sure we don't run into issues +# with smaller xntpd adjustments +(( tdiff=tstop-tstart )) +(( tdiff < (10.-2.) )) || err_exit "test run needed ${tdiff} seconds to complete (instead of < 8.)" + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh b/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh index 2089ad184c..8e1e2ab937 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_getconf.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -38,6 +38,7 @@ function err_exit } alias err_exit='err_exit $LINENO' +set -o nounset Command=${0##*/} integer Errors=0 @@ -56,6 +57,15 @@ export PATH=/usr/bin:/bin # work in compiled shell scripts) typeset -r getconf_test_functions="$( cat <<EOF +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 # compare builtin getconf output with /usr/bin/getconf function compare_normal { @@ -63,13 +73,13 @@ function compare_normal /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) - t="${i%:*}" + t="\${i%:*}" - a="$(getconf "$t" 2>/dev/null)" - b="$(/usr/bin/getconf "$t" 2>/dev/null)" + a="\$(getconf "\$t" 2>/dev/null)" + b="\$(/usr/bin/getconf "\$t" 2>/dev/null)" - if [[ "$a" != "$b" ]] ; then - print -u2 "getconf/normal built mismatch: |$t|:|$a| != |$b|" + if [[ "\$a" != "\$b" ]] ; then + print -u2 "getconf/normal built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done @@ -82,13 +92,13 @@ function compare_path /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) - t="${i%:*}" + t="\${i%:*}" - a="$(getconf "$t" "/tmp" 2>/dev/null)" - b="$(/usr/bin/getconf "$t" "/tmp" 2>/dev/null)" + a="\$(getconf "\$t" "/tmp" 2>/dev/null)" + b="\$(/usr/bin/getconf "\$t" "/tmp" 2>/dev/null)" - if [[ "$a" != "$b" ]] ; then - print -u2 "getconf/path built mismatch: |$t|:|$a| != |$b|" + if [[ "\$a" != "\$b" ]] ; then + print -u2 "getconf/path built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done @@ -108,7 +118,7 @@ do export PATH="${i}" ## test whether the getconf builtin is available - if [[ "$(builtin | fgrep "/bin/getconf")" = "" ]] ; then + if [[ "$(builtin | fgrep "/bin/getconf")" == "" ]] ; then err_exit '/bin/getconf not found in the list of builtins.' fi @@ -161,5 +171,6 @@ do (( Errors+=$? )) done + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh b/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh index 30a2deb314..e95a502daf 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_local_compound_nameref001.sh @@ -28,17 +28,20 @@ # name reference test #001 # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + function function2 { nameref v=$1 @@ -60,5 +63,6 @@ x="$(function1)" [[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'" + # tests done exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh b/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh index 9230c9925f..9f430d7c1c 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_staticvariables.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -45,8 +45,11 @@ function testfunc alias testfunc='testfunc $LINENO' alias err_exit='err_exit2 $LINENO' +set -o nounset +Command=${0##*/} integer Errors=0 + # string testfunc '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh index 74783e6ff7..bf5257a78a 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree001.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -50,15 +50,17 @@ # [14] main(argc = 2, argv = 0xffffffff7ffffa08), line 46 in "pmain.c" # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh index e233f596e3..c2ca8f5e5e 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree002.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -31,22 +31,24 @@ # and "unset" handling. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 # "built_tree1" and "built_tree2" are identical except the way how they test # whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content -# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +# - "built_tree2" uses "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", e.g. "unset" in a subshell. function build_tree1 { #set -o errexit -o xtrace @@ -113,7 +115,7 @@ function build_tree1 # whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content -# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +# - "built_tree2" uses "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", e.g. "unset" in a subshell. function build_tree2 { #set -o errexit -o xtrace @@ -144,12 +146,12 @@ function build_tree2 [[ "$c" == "" ]] && c='-' #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then - if ! (unset dest_tree.l1["$a"]) ; then + if ! ([[ -v dest_tree.l1["$a"] ]] ; res=$? ; unset dest_tree.l1["$a"] ; exit $res) ; then typeset -A dest_tree.l1["$a"].l2 fi #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then - if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + if ! ([[ -v dest_tree.l1["$a"].l2["$b"] ]] ; res=$? ; unset dest_tree.l1["$a"].l2["$b"] ; exit $res) ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3 fi @@ -301,43 +303,47 @@ function main #### test "unset" in a subshell - ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." - ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." # remove parent node (array element) and then check whether the child is gone, too: ( set -o errexit unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' - ! unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Global: Parent node removed (array element), child still exists" ( set -o errexit unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Local: Parent node removed (array element), child still exists" # remove parent node (array variable) and then check whether the child is gone, too: ( set -o errexit unset 'mytree_local1.l1[urw].l2' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Global: Parent node removed (array variable), child still exists" ( set -o errexit unset 'mytree_local1.l1[urw].l2' - ! unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + ! [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ) || err_exit "Local: Parent node removed (array variable), child still exists" #### test "unset" and compare trees - unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + (( res == 0 )) || err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' + (( res == 0 )) || err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." # Compare trees (after "unset") diff --git a/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh b/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh index 89bc9e7541..1bab7006c3 100644 --- a/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh +++ b/usr/src/lib/libshell/common/tests/sun_solaris_vartree003.sh @@ -20,7 +20,7 @@ # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -31,15 +31,17 @@ # and "unset" handling. # +# test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" - (( Errors+=1 )) + (( Errors++ )) } - alias err_exit='err_exit $LINENO' +# the test cannot use "nounset" +Command=${0##*/} integer Errors=0 function example_tree diff --git a/usr/src/lib/libshell/common/tests/tilde.sh b/usr/src/lib/libshell/common/tests/tilde.sh index 60a2de0aa8..e22626f6df 100644 --- a/usr/src/lib/libshell/common/tests/tilde.sh +++ b/usr/src/lib/libshell/common/tests/tilde.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -25,6 +25,12 @@ function err_exit } alias err_exit='err_exit $LINENO' +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + function home # id { typeset IFS=: pwd=/etc/passwd @@ -36,8 +42,6 @@ function home # id fi } -Command=${0##*/} -integer Errors=0 OLDPWD=/bin if [[ ~ != $HOME ]] then err_exit '~' not $HOME @@ -69,24 +73,23 @@ do h=$(home $u) if [[ $h != . ]] then [[ ~$u -ef $h ]] || err_exit "~$u not $h" x=~$u - [[ $x -ef $h ]] || "x=~$u not $h" + [[ $x -ef $h ]] || x="~$u not $h" break fi done -x=~%% -if [[ $x != '~%%' ]] -then err_exit 'x='~%%' not '~%% +x=~g.r.emlin +if [[ $x != '~g.r.emlin' ]] +then err_exit "x=~g.r.emlin failed -- expected '~g.r.emlin', got '$x'" fi x=~:~ if [[ $x != "$HOME:$HOME" ]] -then err_exit x=~:~ not $HOME:$HOME +then err_exit "x=~:~ failed, expected '$HOME:$HOME', got '$x'" fi HOME=/ [[ ~ == / ]] || err_exit '~ should be /' -trap 'rm -rf /tmp/kshtilde$$' EXIT [[ ~/foo == /foo ]] || err_exit '~/foo should be /foo when ~==/' -print $'print ~+\n[[ $1 ]] && $0' > /tmp/kshtilde$$ -chmod +x /tmp/kshtilde$$ +print $'print ~+\n[[ $1 ]] && $0' > $tmp/tilde +chmod +x $tmp/tilde nl=$'\n' -[[ $(/tmp/kshtilde$$ foo) == "$PWD$nl$PWD" ]] 2> /dev/null || err_exit 'tilde fails inside a script run by name' +[[ $($tmp/tilde foo) == "$PWD$nl$PWD" ]] 2> /dev/null || err_exit 'tilde fails inside a script run by name' exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/timetype.sh b/usr/src/lib/libshell/common/tests/timetype.sh index c2046d5272..94b27843f1 100644 --- a/usr/src/lib/libshell/common/tests/timetype.sh +++ b/usr/src/lib/libshell/common/tests/timetype.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # diff --git a/usr/src/lib/libshell/common/tests/treemove.sh b/usr/src/lib/libshell/common/tests/treemove.sh new file mode 100644 index 0000000000..9e83e35e50 --- /dev/null +++ b/usr/src/lib/libshell/common/tests/treemove.sh @@ -0,0 +1,85 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether "typeset -m" correctly moves local variables +# into a global variable tree. +# +# This was reported as CR #XXXXXXXX ("XXXX"): +# -- snip -- +#XXXX +# -- snip -- +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +## test start +typeset -C tree1 tree2 + +# add node to tree which uses "typeset -m" to move a local variable +# into tree1.subtree["a_node"] +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + # move local note into the array +false + typeset -m tr.subtree["a_node"]=node + return 0 +} + +# Alternative version which uses "nameref" instead of "typeset -m" +function f2 +{ + nameref tr=$1 + typeset -A tr.subtree + nameref node=tr.subtree["a_node"] + node.one="hello" + node.two="world" + return 0 +} + +f1 tree1 +f2 tree2 + +[[ "${tree1.subtree["a_node"].one}" == "hello" ]] || err_exit "expected tree1.subtree[\"a_node\"].one == 'hello', got ${tree1.subtree["a_node"].one}" +[[ "${tree1.subtree["a_node"].two}" == "world" ]] || err_exit "expected tree1.subtree[\"a_node\"].two == 'world', got ${tree1.subtree["a_node"].two}" +[[ "${tree1}" == "${tree2}" ]] || err_exit "tree1 and tree2 differ:$'\n'" + +# tests done +exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/types.sh b/usr/src/lib/libshell/common/tests/types.sh index 24be9e9863..5904640e07 100644 --- a/usr/src/lib/libshell/common/tests/types.sh +++ b/usr/src/lib/libshell/common/tests/types.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -27,6 +27,10 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + integer n=2 typeset -T Type_t=( @@ -109,14 +113,13 @@ x=(a b c) typeset -m x[1]=x[2] [[ ${x[1]} == c ]] || err_exit 'move an indexed array element fails' [[ ${x[2]} ]] && err_exit 'x[2] should be unset after move' -trap 'rm -f /tmp/kshtype$$' EXIT -cat > /tmp/kshtype$$ <<- \+++ +cat > $tmp/types <<- \+++ typeset -T Pt_t=(float x=1. y=0.) Pt_t p=(y=2) print -r -- ${p.y} +++ expected=2 -got=$(. /tmp/kshtype$$) 2>/dev/null +got=$(. $tmp/types) 2>/dev/null [[ "$got" == "$expected" ]] || err_exit "typedefs in dot script failed -- expected '$expected', got '$got'" typeset -T X_t=( typeset x=foo y=bar @@ -263,6 +266,114 @@ $SHELL > /dev/null <<- '+++++' || err_exit 'passing _ as nameref arg not workin function f { f1 _ ;} ) A_t a - [[ ${ a.f ./t1;} == "$a" ]] + [[ ${ a.f ./t1;} == "$a" ]] +++++ +expected='A_t b.a=(name=one;)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name=aha + ) + typeset -T B_t=( + typeset arr + A_t a + f() + { + _.a=(name=one) + typeset -p _.a + } + ) + B_t b + b.f ++++ +) == "$expected" ]] 2> /dev/null || err_exit '_.a=(name=one) not expanding correctly' +expected='A_t x=(name=xxx;)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name + ) + A_t x=(name="xxx") + typeset -p x ++++ +) == "$expected" ]] || err_exit 'empty field in definition does not expand correctly' + +typeset -T Foo_t=( + integer x=3 + integer y=4 + len() { print -r -- $(( sqrt(_.x**2 + _.y**2))) ;} +) +Foo_t foo +[[ ${foo.len} == 5 ]] || err_exit "discipline function len not working" + +typeset -T benchmark_t=( + integer num_iterations +) +function do_benchmarks +{ + nameref tst=b + integer num_iterations + (( num_iterations= int(tst.num_iterations * 1.0) )) + printf "%d\n" num_iterations +} +benchmark_t b=(num_iterations=5) +[[ $(do_benchmarks) == 5 ]] || err_exit 'scoping of nameref of type variables in arithmetic expressions not working' + +function cat_content +{ + cat <<- EOF + ( + foo_t -a foolist=( + ( val=3 ) + ( val=4 ) + ( val=5 ) + ) + ) + EOF + return 0 +} +typeset -T foo_t=( + integer val=-1 + function print + { + print -- ${_.val} + } +) +function do_something +{ + nameref li=$1 # "li" may be an index or associative array + li[2].print +} +cat_content | read -C x +[[ $(do_something x.foolist) == 5 ]] || err_exit 'subscripts not honored for arrays of type with disciplines' + +typeset -T benchcmd_t=( + float x=1 + float y=2 +) +unset x +compound x=( + float o + benchcmd_t -a m + integer h +) +expected=$'(\n\ttypeset -l -i h=0\n\tbenchcmd_t -a m\n\ttypeset -l -E o=0\n)' +[[ $x == "$expected" ]] || err_exit 'compound variable with array of types with no elements not working' + +expected=$'Std_file_t db.file[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)' +{ + got=$($SHELL <<- \EOF + MAGIC='stdinstall (at&t research) 2009-08-25' + typeset -T Std_file_t=( + typeset action + typeset -A sum + ) + typeset -T Std_t=( + typeset magic=$MAGIC + Std_file_t -A file + ) + Std_t db=(magic='stdinstall (at&t research) 2009-08-25';Std_file_t -A file=( [/./home/gsf/.env.sh]=(action=preserve;typeset -A sum=([9b67ab407d01a52b3e73e3945b9a3ee0]=1);)[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)[/home/gsf/.profile]=(action=preserve;typeset -A sum=([3ce23137335219672bf2865d003a098e]=1);));) + typeset -p db.file[/etc/profile] + EOF) +} 2> /dev/null +[[ $got == "$expected" ]] || err_exit 'types with arrays of types as members fails' + exit $Errors diff --git a/usr/src/lib/libshell/common/tests/variables.sh b/usr/src/lib/libshell/common/tests/variables.sh index 1808d2fbcf..f174a9a2bf 100644 --- a/usr/src/lib/libshell/common/tests/variables.sh +++ b/usr/src/lib/libshell/common/tests/variables.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -28,11 +28,14 @@ alias err_exit='err_exit $LINENO' Command=${0##*/} integer Errors=0 +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + [[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION' unset ss -[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' -[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' -[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' +[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' +[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' +[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' # RANDOM if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) then err_exit RANDOM variable not working @@ -57,17 +60,19 @@ fi #fi # PWD if [[ ! $PWD -ef . ]] -then err_exit PWD variable not working +then err_exit PWD variable failed, not equivalent to . fi # PPID -if [[ $($SHELL -c 'print $PPID') != $$ ]] -then err_exit PPID variable not working +exp=$$ +got=${ $SHELL -c 'print $PPID'; } +if [[ ${ $SHELL -c 'print $PPID'; } != $$ ]] +then err_exit "PPID variable failed -- expected '$exp', got '$got'" fi # OLDPWD old=$PWD cd / if [[ $OLDPWD != $old ]] -then err_exit OLDPWD variable not working +then err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'" fi cd $old || err_exit cd failed # REPLY @@ -90,7 +95,7 @@ LINENO=save+10 IFS=: x=a::b::c if [[ $x != a::b::c ]] -then err_exit "Word splitting on constants" +then err_exit "word splitting on constants" fi set -- $x if [[ $# != 5 ]] @@ -171,7 +176,7 @@ unset -n foo foo=junk function foo.get { - .sh.value=stuff + .sh.value=stuff unset -f foo.get } if [[ $foo != stuff ]] @@ -209,22 +214,19 @@ done kill $! unset x CDPATH=/ -x=$(cd tmp) -if [[ $x != /tmp ]] +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] then err_exit 'CDPATH does not display new directory' fi -mkdir /tmp/ksh$$ CDPATH=/: -x=$(cd /tmp;cd ksh$$) +x=$(cd ${tmp%/*}; cd ${tmp##*/}) if [[ $x ]] then err_exit 'CDPATH displays new directory when not used' fi -x=$(cd tmp/ksh$$) -if [[ $x != /tmp/ksh$$ ]] -then err_exit "CDPATH tmp/ksh$$ does not display new directory" +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] +then err_exit "CDPATH ${tmp#/} does not display new directory" fi -cd / -rm -rf /tmp/ksh$$ TMOUT=100 (TMOUT=20) if (( TMOUT !=100 )) @@ -411,15 +413,15 @@ done unset IFS if [[ $( (print ${12345:?}) 2>&1) != *12345* ]] -then err_exit 'Incorrect error message with ${12345?}' +then err_exit 'incorrect error message with ${12345?}' fi unset foobar if [[ $( (print ${foobar:?}) 2>&1) != *foobar* ]] -then err_exit 'Incorrect error message with ${foobar?}' +then err_exit 'incorrect error message with ${foobar?}' fi unset bar if [[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]] -then err_exit 'Incorrect error message with ${foobar?}' +then err_exit 'incorrect error message with ${foobar?}' fi { $SHELL -c ' function foo @@ -427,14 +429,13 @@ function foo typeset SECONDS=0 sleep 1.5 print $SECONDS - + } x=$(foo) -(( x >1 && x < 2 )) +(( x >1 && x < 2 )) ' } 2> /dev/null || err_exit 'SECONDS not working in function' -trap 'rm -f /tmp/script$$ /tmp/out$$' EXIT -cat > /tmp/script$$ <<-\! +cat > $tmp/script <<-\! posixfun() { unset x @@ -451,12 +452,12 @@ cat > /tmp/script$$ <<-\! else print -r -- "${.sh.file}" fi ! -chmod +x /tmp/script$$ -. /tmp/script$$ 1 -[[ $file == /tmp/script$$ ]] || err_exit ".sh.file not working for dot scripts" -[[ $($SHELL /tmp/script$$) == /tmp/script$$ ]] || err_exit ".sh.file not working for scripts" -[[ $(posixfun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for posix functions" -[[ $(fun .sh.file) == /tmp/script$$ ]] || err_exit ".sh.file not working for functions" +chmod +x $tmp/script +. $tmp/script 1 +[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts" +[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts" +[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions" +[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions" [[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions" [[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions" [[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions" @@ -483,22 +484,22 @@ function dave.unset unset dave [[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed' -print 'print ${VAR}' > /tmp/script$$ +print 'print ${VAR}' > $tmp/script unset VAR -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'" [[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'" unset VAR VAR=old -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'" [[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'" unset VAR export VAR=old -VAR=new /tmp/script$$ > /tmp/out$$ -got=$(</tmp/out$$) +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) [[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'" [[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'" @@ -511,7 +512,7 @@ got=$(</tmp/out$$) } dave=foo; dave+=bar [[ $dave == barfoo ]] || exit 2 -) 2> /dev/null +) 2> /dev/null case $? in 0) ;; 1) err_exit 'append discipline not implemented';; @@ -522,8 +523,8 @@ esac function .sh.foobar.get { .sh.value=world - } -} 2> /dev/null || err_exit "Can't add get discipline to .sh.foobar" + } +} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar" [[ ${.sh.foobar} == world ]] || err_exit 'get discipline for .sh.foobar not working' x='a|b' IFS='|' @@ -557,12 +558,12 @@ function foo.set ;; esac } -foo[barrier_hit]=no +foo[barrier_hit]=no foo[bar]=1 (( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1' [[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no' [[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes' -foo[barrier_hit]=no +foo[barrier_hit]=no foo[bar]=2 (( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5' [[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes' @@ -576,8 +577,10 @@ function x.set } x[0]=0 x[1]=1 x[2]=2 x[3]=3 [[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly' +float seconds ((SECONDS=3*4)) -(( SECONDS < 12 || SECONDS > 12.1 )) && err_exit "SECONDS is $SECONDS and should be close to 12" +seconds=SECONDS +(( seconds < 12 || seconds > 12.1 )) && err_exit "SECONDS is $seconds and should be close to 12" unset a function a.set { @@ -611,15 +614,37 @@ do nameref r=$v else err_exit "unset $v; : \$$v failed" fi done + +x=x for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC do nameref r=$v unset $v [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" d=$($SHELL -c "$v=$x" 2>&1) [[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic" - ( r=$x; [[ ! $r ]] ) 2>/dev/null || err_exit "$v=$x failed -- expected ''" - ( r=C; r=$x; [[ $r == C ]] ) 2>/dev/null || err_exit "$v=C; $v=$x failed -- expected 'C'" + { g=$( r=$x; print -- $r ); } 2>/dev/null + [[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'" + { g=$( r=C; r=$x; print -- $r ); } 2>/dev/null + [[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'" done PATH=$path +cd $tmp + +print print -n zzz > zzz +chmod +x zzz +exp='aaazzz' +got=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1 +[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'" + +mkdir glean +for cmd in date ok +do exp="$cmd ok" + rm -f $cmd + print print $exp > glean/$cmd + chmod +x glean/$cmd + got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1) + [[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'" +done + exit $((Errors)) diff --git a/usr/src/lib/libshell/common/tests/vartree1.sh b/usr/src/lib/libshell/common/tests/vartree1.sh index 88116a24c3..67134086af 100644 --- a/usr/src/lib/libshell/common/tests/vartree1.sh +++ b/usr/src/lib/libshell/common/tests/vartree1.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -41,7 +41,7 @@ function build_tree typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -53,15 +53,15 @@ function build_tree for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then #if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -75,7 +75,7 @@ function build_tree if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + #dest_tree.l1["$a"].l2["$b"].l3["$c"].entries+=( "$index" ) typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then @@ -88,12 +88,12 @@ function build_tree continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } function add_tree_leaf @@ -101,7 +101,7 @@ function add_tree_leaf nameref tree_leafnode="$1" nameref data_node=srcdata.hashnodes["$2"] typeset add_mode="$3" - + case "${add_mode}" in "leaf_name") tree_leafnode="${data_node.name}" @@ -121,7 +121,7 @@ function add_tree_leaf return 1 ;; esac - + # not reached return 1 } @@ -151,7 +151,7 @@ typeset mysrcdata_global=( ) mytree_global=() - + function main { # "mysrcdata_local" and "mysrcdata_global" must be identical @@ -182,32 +182,32 @@ function main build_tree mytree_global mysrcdata_global leaf_compound || \ err_exit 'build_tree mytree_global mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global' too small." + (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global' too small" # build tree using local tree variables mytree_local=() build_tree mytree_local mysrcdata_local leaf_compound || \ err_exit 'build_tree mytree_local mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local' too small." - + (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local' too small" + # Compare trees if [[ "${mytree_global}" != "${mytree_local}" ]] ; then - err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical" + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical" fi - + unset 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + [[ "${mytree_global}" != "${mytree_local}" ]] || err_exit "mytree_global and mytree_local should differ" unset 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + # Compare trees (after "unset") if [[ "${mytree_global}" != "${mytree_local}" ]] ; then - err_exit "Compound trees 'mytree_local' and 'mytree_global' not identical after unset" - fi + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical after unset" + fi } main diff --git a/usr/src/lib/libshell/common/tests/vartree2.sh b/usr/src/lib/libshell/common/tests/vartree2.sh index 38512d5a42..9f478ae140 100644 --- a/usr/src/lib/libshell/common/tests/vartree2.sh +++ b/usr/src/lib/libshell/common/tests/vartree2.sh @@ -1,7 +1,7 @@ ######################################################################## # # # This software is part of the ast package # -# Copyright (c) 1982-2008 AT&T Intellectual Property # +# Copyright (c) 1982-2009 AT&T Intellectual Property # # and is licensed under the # # Common Public License, Version 1.0 # # by AT&T Intellectual Property # @@ -34,7 +34,7 @@ function err_exit alias err_exit='err_exit $LINENO' # "built_tree1" and "built_tree2" are identical except the way how they test -# whether a variable exists: +# whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content # - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell @@ -46,7 +46,7 @@ function build_tree1 typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -58,15 +58,15 @@ function build_tree1 for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then #if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -80,7 +80,7 @@ function build_tree1 if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) @@ -92,16 +92,16 @@ function build_tree1 continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } # "built_tree1" and "built_tree2" are identical except the way how they test -# whether a variable exists: +# whether a variable exists: # - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable # as non-zero length content # - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell @@ -113,7 +113,7 @@ function build_tree2 typeset i typeset dummy typeset a b c d e f - + nameref dest_tree="$1" # destination tree nameref srcdata="$2" # source data typeset tree_mode="$3" # mode to define the type of leads @@ -125,15 +125,15 @@ function build_tree2 for i in "${node.xlfd[@]}" ; do IFS='-' read dummy a b c d e f <<<"$i" - + if [[ "$a" == "" ]] ; then a="$dummy" fi - + [[ "$a" == "" ]] && a='-' [[ "$b" == "" ]] && b='-' [[ "$c" == "" ]] && c='-' - + #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then if ! (unset dest_tree.l1["$a"]) ; then typeset -A dest_tree.l1["$a"].l2 @@ -147,7 +147,7 @@ function build_tree2 if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries fi - + typeset new_index if [[ "${tree_mode}" == "leaf_name" ]] ; then new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) @@ -159,12 +159,12 @@ function build_tree2 continue fi fi - + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" done done - - return 0 + + return 0 } @@ -173,7 +173,7 @@ function add_tree_leaf nameref tree_leafnode="$1" nameref data_node=srcdata.hashnodes["$2"] typeset add_mode="$3" - + case "${add_mode}" in "leaf_name") tree_leafnode="${data_node.name}" @@ -193,7 +193,7 @@ function add_tree_leaf return 1 ;; esac - + # not reached return 1 } @@ -224,7 +224,7 @@ typeset mysrcdata_global=( mytree_global1=() mytree_global2=() - + function main { # "mysrcdata_local" and "mysrcdata_global" must be identical @@ -254,11 +254,11 @@ function main #### Build tree using global tree variables build_tree1 mytree_global1 mysrcdata_global leaf_compound || \ err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global1' too small." + (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global1' too small" build_tree2 mytree_global2 mysrcdata_global leaf_compound || \ err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error' - (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_global2' too small." + (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global2' too small" #### build tree using local tree variables @@ -267,67 +267,67 @@ function main build_tree1 mytree_local1 mysrcdata_local leaf_compound || \ err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local1' too small." + (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local1' too small" build_tree2 mytree_local2 mysrcdata_local leaf_compound || \ err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error' - (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "Compound tree 'mytree_local2' too small." + (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local2' too small" + - #### Compare treess if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then - err_exit "Compound trees 'mytree_global1' and 'mytree_local1' not identical" + err_exit "compound trees 'mytree_global1' and 'mytree_local1' not identical" fi if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then - err_exit "Compound trees 'mytree_global1' and 'mytree_global2' not identical" + err_exit "compound trees 'mytree_global1' and 'mytree_global2' not identical" fi if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then - err_exit "Compound trees 'mytree_local1' and 'mytree_local2' not identical" + err_exit "compound trees 'mytree_local1' and 'mytree_local2' not identical" fi #### test "unset" in a subshell ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ - err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + err_exit "try 1: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ - err_exit "Try 2: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." + err_exit "try 2: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" # remove parent node (array element) and then check whether the child is gone, too: ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' - unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Global: Parent node removed (array element), child still exists" + [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]'} ]] + ) && err_exit "global: parent node removed (array element), child still exists" ( unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Local: Parent node removed (array element), child still exists" - + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array element), child still exists" + # remove parent node (array variable) and then check whether the child is gone, too: ( unset 'mytree_local1.l1[urw].l2' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Global: Parent node removed (array variable), child still exists" + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "global: parent node removed (array variable), child still exists" ( unset 'mytree_local1.l1[urw].l2' - unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' - ) && err_exit "Local: Parent node removed (array variable), child still exists" + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array variable), child still exists" #### test "unset" and compare trees unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || - err_exit "Variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found." - + err_exit "variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + # Compare trees (after "unset") if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then - err_exit "Compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" - fi + err_exit "compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" + fi } main |