sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / lib / libshell / common / tests / sun_solaris_command_substitution.sh
blob468b533900f9106e859245847785d9a298d08f5d
2 # CDDL HEADER START
4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
19 # CDDL HEADER END
23 # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 # Written by Roland Mainz <roland.mainz@nrubsig.org>
30 # test setup
31 function err_exit
33 print -u2 -n "\t"
34 print -u2 -r ${Command}[$1]: "${@:2}"
35 (( Errors < 127 && Errors++ ))
37 alias err_exit='err_exit $LINENO'
39 set -o nounset
40 Command=${0##*/}
41 integer Errors=0
44 function isvalidpid
46 kill -0 ${1} 2>/dev/null && return 0
47 return 1
49 integer testfilesize i maxwait
50 typeset tmpfile
51 integer testid
54 ########################################################################
55 #### test set 001:
56 # run loop and check various temp filesizes
57 # (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh)
59 # test 1: run loop and check various temp filesizes
60 tmpfile="$(mktemp -t "ksh93_tests_command_substitution.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file."
62 compound test1=(
63 compound -a testcases=(
64 # test 1a: Run test child for $(...)
65 # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug)
66 ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
67 # test 1b: Same as test1a but uses ${... ; } instead if $(...)
68 ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
69 # test 1c: Same as test1a but does not use a pipe
70 ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
71 # test 1d: Same as test1a but does not use a pipe
72 ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
74 # test 1e: Same as test1a but uses an external "cat" command
75 ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
76 # test 1f: Same as test1a but uses an external "cat" command
77 ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
78 # test 1g: Same as test1a but uses an external "cat" command
79 ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
80 # test 1h: Same as test1a but uses an external "cat" command
81 ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
85 for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do
86 # Create temp file
88 for (( i=0 ; i < testfilesize ; i+=64 )) ; do
89 print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE"
90 done
91 } >"${tmpfile}"
93 # wait up to log2(i) seconds for the child to terminate
94 # (this is 10 seconds for 1KB and 19 seconds for 512KB)
95 (( maxwait=log2(testfilesize) ))
97 for testid in "${!test1.testcases[@]}" ; do
98 nameref currtst=test1.testcases[testid]
99 ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
100 (( childpid=$! ))
102 for (( i=0 ; i < maxwait ; i++ )) ; do
103 isvalidpid ${childpid} || break
104 sleep 0.25
105 done
107 if isvalidpid ${childpid} ; then
108 err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}."
109 kill -KILL ${childpid} 2>/dev/null
111 wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
113 # compare input/output
114 cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}."
115 rm "${tmpfile}.out"
116 done
118 # Cleanup
119 rm "${tmpfile}"
120 done
123 ########################################################################
124 #### test set 002:
125 # If a command substitution calls a function and that function contains
126 # a command substitution which contains a piped command, the original
127 # command substitution calling the function will return 127 instead of 0.
128 # This is causing problems in several VSC tests.
129 # If we remove the piped command from the simple
130 # case in the attached script, it returns 0.
132 typeset str
133 typeset testbody
134 typeset testout
136 testbody=$(
137 # <CS> means command substitution start, <CE> means command substitution end
138 cat <<EOF
139 myfunc ()
141 pipedcmd=<CS> printf "hi" | tr "h" "H" <CE>
142 echo \$pipedcmd
144 return 0
147 foo=<CS>myfunc<CE>
148 retval=\$?
150 if [ "\$foo"X != "HiX" ]; then
151 echo "myfunc returned '\${foo}'; expected 'Hi'"
154 if [ \$retval -ne 0 ]; then
155 echo "command substitution calling myfunc returned \"\${retval}\"; expected 0"
156 else
157 echo "command substitution calling myfunc successfully returned 0"
163 # Test 002/a: Plain test
164 testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
165 [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
167 # Test 002/b: Same as test002/a but replaces "$(" with "${"
168 testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
169 [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
171 # Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0"
172 testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
173 [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
175 # Test 002/d: Same as test002/a but uses extra subshell
176 testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
177 [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
179 # Test 002/e: Same as test002/b but uses extra subshell after "${ "
180 testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
181 [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
186 ########################################################################
187 #### test set 003:
188 # An expression within backticks which should return false, instead
189 # returns true (0).
191 typeset str
192 typeset testbody
193 typeset testout
195 testbody=$(
196 # <CS> means command substitution start, <CE> means command substitution end
197 cat <<EOF
198 if <CS>expr "NOMATCH" : ".*Z" > /dev/null<CE> ; then
199 echo "xerror"
200 else
201 echo "xok"
207 # Test 003/a: Plain test
208 testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
209 [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
211 # Test 003/b: Same as test003/a but replaces "$(" with "${"
212 testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
213 [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
215 # Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0"
216 testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
217 [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
219 # Test 003/d: Same as test003/a but uses extra subshell
220 testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
221 [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
223 # Test 003/e: Same as test003/b but uses extra subshell after "${ "
224 testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
225 [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
228 ########################################################################
229 #### test set 004:
230 # test pipe within ${... ; } command subtitution ending in a
231 # non-builtin command (therefore we use "/bin/cat" instead of "cat" below
232 # to force the use of the external "cat" command). ast-ksh.2009-01-20
233 # had a bug which caused this test to fail.
234 testout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' )
235 [[ "${testout}" == "hi" ]] || err_exit "test004: Expected 'hi', got '${testout}'"
238 ########################################################################
239 #### test set 005:
240 # Test whether the shell may hang in a
241 # 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)'
242 # Originally discovered with ast-ksh.2009-05-05 which hung in
243 # the "configure" script of postgresql-8.3.7.tar.gz (e.g.
244 # configure --enable-thread-safety --without-readline)
245 compound test5=(
246 compound -a testcases=(
247 # gsf's reduced testcase
248 ( name="test5_a" cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' )
249 # gisburn's reduced testcase
250 ( name="test5_b" cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' )
252 ## The following tests do not trigger the problem but are included here for completeness
253 ## and to make sure we don't get other incarnations of the same problem later...
255 # same as test5_a but uses ${ ... ; } instead of $(...)
256 ( name="test5_c" cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' )
257 # same as test5_b but uses ${ ... ; } instead of $(...)
258 ( name="test5_d" cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' )
259 # same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)
260 ( name="test5_e" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' )
261 # same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)
262 ( name="test5_f" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' )
266 maxwait=5
267 for testid in "${!test5.testcases[@]}" ; do
268 nameref currtst=test5.testcases[testid]
269 ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
270 (( childpid=$! ))
272 for (( i=0 ; i < maxwait ; i++ )) ; do
273 isvalidpid ${childpid} || break
274 sleep 0.25
275 done
277 if isvalidpid ${childpid} ; then
278 err_exit "${currtst.name}: child (pid=${childpid}) still busy."
279 kill -KILL ${childpid} 2>/dev/null
281 wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
283 testout="$( < "${tmpfile}.out")"
284 rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed."
285 [[ "${testout}" == "done" ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'"
286 done
289 # tests done
290 exit $((Errors))