110898Sroland.mainz@nrubsig.org#
210898Sroland.mainz@nrubsig.org# CDDL HEADER START
310898Sroland.mainz@nrubsig.org#
410898Sroland.mainz@nrubsig.org# The contents of this file are subject to the terms of the
510898Sroland.mainz@nrubsig.org# Common Development and Distribution License (the "License").
610898Sroland.mainz@nrubsig.org# You may not use this file except in compliance with the License.
710898Sroland.mainz@nrubsig.org#
810898Sroland.mainz@nrubsig.org# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910898Sroland.mainz@nrubsig.org# or http://www.opensolaris.org/os/licensing.
1010898Sroland.mainz@nrubsig.org# See the License for the specific language governing permissions
1110898Sroland.mainz@nrubsig.org# and limitations under the License.
1210898Sroland.mainz@nrubsig.org#
1310898Sroland.mainz@nrubsig.org# When distributing Covered Code, include this CDDL HEADER in each
1410898Sroland.mainz@nrubsig.org# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510898Sroland.mainz@nrubsig.org# If applicable, add the following below this CDDL HEADER, with the
1610898Sroland.mainz@nrubsig.org# fields enclosed by brackets "[]" replaced with your own identifying
1710898Sroland.mainz@nrubsig.org# information: Portions Copyright [yyyy] [name of copyright owner]
1810898Sroland.mainz@nrubsig.org#
1910898Sroland.mainz@nrubsig.org# CDDL HEADER END
2010898Sroland.mainz@nrubsig.org#
2110898Sroland.mainz@nrubsig.org
2210898Sroland.mainz@nrubsig.org#
23*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2410898Sroland.mainz@nrubsig.org#
2510898Sroland.mainz@nrubsig.org
2610898Sroland.mainz@nrubsig.org#
2710898Sroland.mainz@nrubsig.org# Written by Roland Mainz <roland.mainz@nrubsig.org>
2810898Sroland.mainz@nrubsig.org#
2910898Sroland.mainz@nrubsig.org
3010898Sroland.mainz@nrubsig.org# test setup
3110898Sroland.mainz@nrubsig.orgfunction err_exit
3210898Sroland.mainz@nrubsig.org{
3310898Sroland.mainz@nrubsig.org	print -u2 -n "\t"
3410898Sroland.mainz@nrubsig.org	print -u2 -r ${Command}[$1]: "${@:2}"
35*12068SRoger.Faulkner@Oracle.COM	(( Errors < 127 && Errors++ ))
3610898Sroland.mainz@nrubsig.org}
3710898Sroland.mainz@nrubsig.orgalias err_exit='err_exit $LINENO'
3810898Sroland.mainz@nrubsig.org
3910898Sroland.mainz@nrubsig.orgset -o nounset
4010898Sroland.mainz@nrubsig.orgCommand=${0##*/}
4110898Sroland.mainz@nrubsig.orginteger Errors=0
4210898Sroland.mainz@nrubsig.org
4310898Sroland.mainz@nrubsig.org
4410898Sroland.mainz@nrubsig.orgfunction isvalidpid
4510898Sroland.mainz@nrubsig.org{
4610898Sroland.mainz@nrubsig.org	kill -0 ${1} 2>/dev/null && return 0
4710898Sroland.mainz@nrubsig.org	return 1
4810898Sroland.mainz@nrubsig.org}
4910898Sroland.mainz@nrubsig.orginteger testfilesize i maxwait
5010898Sroland.mainz@nrubsig.orgtypeset tmpfile
5110898Sroland.mainz@nrubsig.orginteger testid
5210898Sroland.mainz@nrubsig.org
5310898Sroland.mainz@nrubsig.org
5410898Sroland.mainz@nrubsig.org########################################################################
5510898Sroland.mainz@nrubsig.org#### test set 001:
5610898Sroland.mainz@nrubsig.org# run loop and check various temp filesizes
5710898Sroland.mainz@nrubsig.org# (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh)
5810898Sroland.mainz@nrubsig.org
5910898Sroland.mainz@nrubsig.org# test 1: run loop and check various temp filesizes
60*12068SRoger.Faulkner@Oracle.COMtmpfile="$(mktemp -t "ksh93_tests_command_substitution.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file."
6110898Sroland.mainz@nrubsig.org
6210898Sroland.mainz@nrubsig.orgcompound test1=(
6310898Sroland.mainz@nrubsig.org	compound -a testcases=(
6410898Sroland.mainz@nrubsig.org		# test 1a: Run test child for $(...)
6510898Sroland.mainz@nrubsig.org		# (note the pipe chain has to end in a builtin command, an external command may not trigger the bug)
6610898Sroland.mainz@nrubsig.org		( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
6710898Sroland.mainz@nrubsig.org		# test 1b: Same as test1a but uses ${... ; } instead if $(...)
6810898Sroland.mainz@nrubsig.org		( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
6910898Sroland.mainz@nrubsig.org		# test 1c: Same as test1a but does not use a pipe
7010898Sroland.mainz@nrubsig.org		( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
7110898Sroland.mainz@nrubsig.org		# test 1d: Same as test1a but does not use a pipe
7210898Sroland.mainz@nrubsig.org		( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
7310898Sroland.mainz@nrubsig.org
7410898Sroland.mainz@nrubsig.org		# test 1e: Same as test1a but uses an external "cat" command
7510898Sroland.mainz@nrubsig.org		( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
7610898Sroland.mainz@nrubsig.org		# test 1f: Same as test1a but uses an external "cat" command
7710898Sroland.mainz@nrubsig.org		( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
7810898Sroland.mainz@nrubsig.org		# test 1g: Same as test1a but uses an external "cat" command
7910898Sroland.mainz@nrubsig.org		( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
8010898Sroland.mainz@nrubsig.org		# test 1h: Same as test1a but uses an external "cat" command
8110898Sroland.mainz@nrubsig.org		( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
8210898Sroland.mainz@nrubsig.org	)
8310898Sroland.mainz@nrubsig.org)
8410898Sroland.mainz@nrubsig.org
8510898Sroland.mainz@nrubsig.orgfor (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do
8610898Sroland.mainz@nrubsig.org	# Create temp file
8710898Sroland.mainz@nrubsig.org	{
8810898Sroland.mainz@nrubsig.org		for (( i=0 ; i < testfilesize ; i+=64 )) ; do
8910898Sroland.mainz@nrubsig.org			print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE"
9010898Sroland.mainz@nrubsig.org		done
9110898Sroland.mainz@nrubsig.org	} >"${tmpfile}"
9210898Sroland.mainz@nrubsig.org
9310898Sroland.mainz@nrubsig.org	# wait up to log2(i) seconds for the child to terminate
9410898Sroland.mainz@nrubsig.org	# (this is 10 seconds for 1KB and 19 seconds for 512KB)
9510898Sroland.mainz@nrubsig.org	(( maxwait=log2(testfilesize) ))
9610898Sroland.mainz@nrubsig.org
9710898Sroland.mainz@nrubsig.org	for testid in "${!test1.testcases[@]}" ; do
9810898Sroland.mainz@nrubsig.org		nameref currtst=test1.testcases[testid]
9910898Sroland.mainz@nrubsig.org		${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
10010898Sroland.mainz@nrubsig.org		(( childpid=$! ))
10110898Sroland.mainz@nrubsig.org
10210898Sroland.mainz@nrubsig.org		for (( i=0 ; i < maxwait ; i++ )) ; do
10310898Sroland.mainz@nrubsig.org			isvalidpid ${childpid} || break
10410898Sroland.mainz@nrubsig.org			sleep 0.25
10510898Sroland.mainz@nrubsig.org		done
10610898Sroland.mainz@nrubsig.org
10710898Sroland.mainz@nrubsig.org		if isvalidpid ${childpid} ; then
10810898Sroland.mainz@nrubsig.org			err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}."
10910898Sroland.mainz@nrubsig.org			kill -KILL ${childpid} 2>/dev/null
11010898Sroland.mainz@nrubsig.org		fi
11110898Sroland.mainz@nrubsig.org		wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
11210898Sroland.mainz@nrubsig.org
11310898Sroland.mainz@nrubsig.org		# compare input/output
11410898Sroland.mainz@nrubsig.org		cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}."
11510898Sroland.mainz@nrubsig.org		rm "${tmpfile}.out"
11610898Sroland.mainz@nrubsig.org	done
11710898Sroland.mainz@nrubsig.org
11810898Sroland.mainz@nrubsig.org	# Cleanup
11910898Sroland.mainz@nrubsig.org	rm "${tmpfile}"
12010898Sroland.mainz@nrubsig.orgdone
12110898Sroland.mainz@nrubsig.org
12210898Sroland.mainz@nrubsig.org
12310898Sroland.mainz@nrubsig.org########################################################################
12410898Sroland.mainz@nrubsig.org#### test set 002:
12510898Sroland.mainz@nrubsig.org# If a command substitution calls a function and that function contains
12610898Sroland.mainz@nrubsig.org# a command substitution which contains a piped command, the original
12710898Sroland.mainz@nrubsig.org# command substitution calling the function will return 127 instead of 0.
12810898Sroland.mainz@nrubsig.org# This is causing problems in several VSC tests.
12910898Sroland.mainz@nrubsig.org# If we remove the piped command from the simple
13010898Sroland.mainz@nrubsig.org# case in the attached script, it returns 0.
13110898Sroland.mainz@nrubsig.org
13210898Sroland.mainz@nrubsig.orgtypeset str
13310898Sroland.mainz@nrubsig.orgtypeset testbody
13410898Sroland.mainz@nrubsig.orgtypeset testout
13510898Sroland.mainz@nrubsig.org
13610898Sroland.mainz@nrubsig.orgtestbody=$(
13710898Sroland.mainz@nrubsig.org# <CS> means command substitution start, <CE> means command substitution end
13810898Sroland.mainz@nrubsig.orgcat <<EOF
13910898Sroland.mainz@nrubsig.orgmyfunc ()
14010898Sroland.mainz@nrubsig.org{ 
14110898Sroland.mainz@nrubsig.org	pipedcmd=<CS> printf "hi" | tr "h" "H" <CE>
14210898Sroland.mainz@nrubsig.org	echo \$pipedcmd
14310898Sroland.mainz@nrubsig.org
14410898Sroland.mainz@nrubsig.org	return 0
14510898Sroland.mainz@nrubsig.org}
14610898Sroland.mainz@nrubsig.org
14710898Sroland.mainz@nrubsig.orgfoo=<CS>myfunc<CE>
14810898Sroland.mainz@nrubsig.orgretval=\$?
14910898Sroland.mainz@nrubsig.org
15010898Sroland.mainz@nrubsig.orgif [ "\$foo"X != "HiX" ]; then
15110898Sroland.mainz@nrubsig.org	echo "myfunc returned '\${foo}'; expected 'Hi'"
15210898Sroland.mainz@nrubsig.orgfi
15310898Sroland.mainz@nrubsig.org
15410898Sroland.mainz@nrubsig.orgif [ \$retval -ne 0 ]; then
15510898Sroland.mainz@nrubsig.org	echo "command substitution calling myfunc returned \"\${retval}\"; expected 0"
15610898Sroland.mainz@nrubsig.orgelse
15710898Sroland.mainz@nrubsig.org	echo "command substitution calling myfunc successfully returned 0"
15810898Sroland.mainz@nrubsig.orgfi
15910898Sroland.mainz@nrubsig.orgEOF
16010898Sroland.mainz@nrubsig.org)
16110898Sroland.mainz@nrubsig.org
16210898Sroland.mainz@nrubsig.org
16310898Sroland.mainz@nrubsig.org# Test 002/a: Plain test
16410898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
16510898Sroland.mainz@nrubsig.org[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
16610898Sroland.mainz@nrubsig.org
16710898Sroland.mainz@nrubsig.org# Test 002/b: Same as test002/a but replaces "$(" with "${"
16810898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
16910898Sroland.mainz@nrubsig.org[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
17010898Sroland.mainz@nrubsig.org
17110898Sroland.mainz@nrubsig.org# Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0"
17210898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
17310898Sroland.mainz@nrubsig.org[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
17410898Sroland.mainz@nrubsig.org
17510898Sroland.mainz@nrubsig.org# Test 002/d: Same as test002/a but uses extra subshell
17610898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
17710898Sroland.mainz@nrubsig.org[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
17810898Sroland.mainz@nrubsig.org
17910898Sroland.mainz@nrubsig.org# Test 002/e: Same as test002/b but uses extra subshell after "${ "
18010898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
18110898Sroland.mainz@nrubsig.org[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"
18210898Sroland.mainz@nrubsig.org
18310898Sroland.mainz@nrubsig.org
18410898Sroland.mainz@nrubsig.org
18510898Sroland.mainz@nrubsig.org
18610898Sroland.mainz@nrubsig.org########################################################################
18710898Sroland.mainz@nrubsig.org#### test set 003:
18810898Sroland.mainz@nrubsig.org# An expression within backticks which should return false, instead
18910898Sroland.mainz@nrubsig.org# returns true (0).
19010898Sroland.mainz@nrubsig.org
19110898Sroland.mainz@nrubsig.orgtypeset str
19210898Sroland.mainz@nrubsig.orgtypeset testbody
19310898Sroland.mainz@nrubsig.orgtypeset testout
19410898Sroland.mainz@nrubsig.org
19510898Sroland.mainz@nrubsig.orgtestbody=$(
19610898Sroland.mainz@nrubsig.org# <CS> means command substitution start, <CE> means command substitution end
19710898Sroland.mainz@nrubsig.orgcat <<EOF
19810898Sroland.mainz@nrubsig.orgif <CS>expr "NOMATCH" : ".*Z" > /dev/null<CE> ; then
19910898Sroland.mainz@nrubsig.org        echo "xerror"
20010898Sroland.mainz@nrubsig.orgelse
20110898Sroland.mainz@nrubsig.org        echo "xok"
20210898Sroland.mainz@nrubsig.orgfi
20310898Sroland.mainz@nrubsig.orgEOF
20410898Sroland.mainz@nrubsig.org)
20510898Sroland.mainz@nrubsig.org
20610898Sroland.mainz@nrubsig.org
20710898Sroland.mainz@nrubsig.org# Test 003/a: Plain test
20810898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
20910898Sroland.mainz@nrubsig.org[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
21010898Sroland.mainz@nrubsig.org
21110898Sroland.mainz@nrubsig.org# Test 003/b: Same as test003/a but replaces "$(" with "${"
21210898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
21310898Sroland.mainz@nrubsig.org[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
21410898Sroland.mainz@nrubsig.org
21510898Sroland.mainz@nrubsig.org# Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0"
21610898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
21710898Sroland.mainz@nrubsig.org[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
21810898Sroland.mainz@nrubsig.org
21910898Sroland.mainz@nrubsig.org# Test 003/d: Same as test003/a but uses extra subshell
22010898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
22110898Sroland.mainz@nrubsig.org[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
22210898Sroland.mainz@nrubsig.org
22310898Sroland.mainz@nrubsig.org# Test 003/e: Same as test003/b but uses extra subshell after "${ "
22410898Sroland.mainz@nrubsig.orgtestout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }
22510898Sroland.mainz@nrubsig.org[[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}"
22610898Sroland.mainz@nrubsig.org
22710898Sroland.mainz@nrubsig.org
22810898Sroland.mainz@nrubsig.org########################################################################
22910898Sroland.mainz@nrubsig.org#### test set 004:
23010898Sroland.mainz@nrubsig.org# test pipe within ${... ; } command subtitution ending in a
23110898Sroland.mainz@nrubsig.org# non-builtin command (therefore we use "/bin/cat" instead of "cat" below
23210898Sroland.mainz@nrubsig.org# to force the use of the external "cat" command). ast-ksh.2009-01-20
23310898Sroland.mainz@nrubsig.org# had a bug which caused this test to fail.
23410898Sroland.mainz@nrubsig.orgtestout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' )
23510898Sroland.mainz@nrubsig.org[[ "${testout}" == "hi" ]] || err_exit "test004: Expected 'hi', got '${testout}'"
23610898Sroland.mainz@nrubsig.org
23710898Sroland.mainz@nrubsig.org
23810898Sroland.mainz@nrubsig.org########################################################################
23910898Sroland.mainz@nrubsig.org#### test set 005:
24010898Sroland.mainz@nrubsig.org# Test whether the shell may hang in a
24110898Sroland.mainz@nrubsig.org# 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)'
24210898Sroland.mainz@nrubsig.org# Originally discovered with ast-ksh.2009-05-05 which hung in
24310898Sroland.mainz@nrubsig.org# the "configure" script of postgresql-8.3.7.tar.gz (e.g.
24410898Sroland.mainz@nrubsig.org# configure --enable-thread-safety --without-readline)
24510898Sroland.mainz@nrubsig.orgcompound test5=(
24610898Sroland.mainz@nrubsig.org	compound -a testcases=(
24710898Sroland.mainz@nrubsig.org		# gsf's reduced testcase
24810898Sroland.mainz@nrubsig.org		( name="test5_a" cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' )
24910898Sroland.mainz@nrubsig.org		# gisburn's reduced testcase
25010898Sroland.mainz@nrubsig.org		( name="test5_b" cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' )
25110898Sroland.mainz@nrubsig.org
25210898Sroland.mainz@nrubsig.org		## The following tests do not trigger the problem but are included here for completeness
25310898Sroland.mainz@nrubsig.org		## and to make sure we don't get other incarnations of the same problem later...
25410898Sroland.mainz@nrubsig.org
25510898Sroland.mainz@nrubsig.org		# same as test5_a but uses ${ ... ; } instead of $(...)
25610898Sroland.mainz@nrubsig.org		( name="test5_c" cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' )
25710898Sroland.mainz@nrubsig.org		# same as test5_b but uses ${ ... ; } instead of $(...)
25810898Sroland.mainz@nrubsig.org		( name="test5_d" cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' )
25910898Sroland.mainz@nrubsig.org		# same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)
26010898Sroland.mainz@nrubsig.org		( name="test5_e" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' )
26110898Sroland.mainz@nrubsig.org		# same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)
26210898Sroland.mainz@nrubsig.org		( name="test5_f" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' )
26310898Sroland.mainz@nrubsig.org	)
26410898Sroland.mainz@nrubsig.org)
26510898Sroland.mainz@nrubsig.org
26610898Sroland.mainz@nrubsig.orgmaxwait=5
26710898Sroland.mainz@nrubsig.orgfor testid in "${!test5.testcases[@]}" ; do
26810898Sroland.mainz@nrubsig.org	nameref currtst=test5.testcases[testid]
26910898Sroland.mainz@nrubsig.org	${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
27010898Sroland.mainz@nrubsig.org	(( childpid=$! ))
27110898Sroland.mainz@nrubsig.org
27210898Sroland.mainz@nrubsig.org	for (( i=0 ; i < maxwait ; i++ )) ; do
27310898Sroland.mainz@nrubsig.org		isvalidpid ${childpid} || break
27410898Sroland.mainz@nrubsig.org		sleep 0.25
27510898Sroland.mainz@nrubsig.org	done
27610898Sroland.mainz@nrubsig.org
27710898Sroland.mainz@nrubsig.org	if isvalidpid ${childpid} ; then
27810898Sroland.mainz@nrubsig.org		err_exit "${currtst.name}: child (pid=${childpid}) still busy."
27910898Sroland.mainz@nrubsig.org		kill -KILL ${childpid} 2>/dev/null
28010898Sroland.mainz@nrubsig.org	fi
28110898Sroland.mainz@nrubsig.org	wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
28210898Sroland.mainz@nrubsig.org
28310898Sroland.mainz@nrubsig.org	testout="$( < "${tmpfile}.out")"
28410898Sroland.mainz@nrubsig.org	rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed."
28510898Sroland.mainz@nrubsig.org	[[ "${testout}" == "done" ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'"
28610898Sroland.mainz@nrubsig.orgdone
28710898Sroland.mainz@nrubsig.org
28810898Sroland.mainz@nrubsig.org
28910898Sroland.mainz@nrubsig.org# tests done
29010898Sroland.mainz@nrubsig.orgexit $((Errors))
291