181af778eSCasper H.S. Dik#
281af778eSCasper H.S. Dik# CDDL HEADER START
381af778eSCasper H.S. Dik#
481af778eSCasper H.S. Dik# The contents of this file are subject to the terms of the
581af778eSCasper H.S. Dik# Common Development and Distribution License (the "License").
681af778eSCasper H.S. Dik# You may not use this file except in compliance with the License.
781af778eSCasper H.S. Dik#
881af778eSCasper H.S. Dik# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
981af778eSCasper H.S. Dik# or http://www.opensolaris.org/os/licensing.
1081af778eSCasper H.S. Dik# See the License for the specific language governing permissions
1181af778eSCasper H.S. Dik# and limitations under the License.
1281af778eSCasper H.S. Dik#
1381af778eSCasper H.S. Dik# When distributing Covered Code, include this CDDL HEADER in each
1481af778eSCasper H.S. Dik# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1581af778eSCasper H.S. Dik# If applicable, add the following below this CDDL HEADER, with the
1681af778eSCasper H.S. Dik# fields enclosed by brackets "[]" replaced with your own identifying
1781af778eSCasper H.S. Dik# information: Portions Copyright [yyyy] [name of copyright owner]
1881af778eSCasper H.S. Dik#
1981af778eSCasper H.S. Dik# CDDL HEADER END
2081af778eSCasper H.S. Dik#
2181af778eSCasper H.S. Dik
2281af778eSCasper H.S. Dik#
233e14f97fSRoger A. Faulkner# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2481af778eSCasper H.S. Dik#
2581af778eSCasper H.S. Dik
2681af778eSCasper H.S. Dik#
2781af778eSCasper H.S. Dik# Test whether CR #6800929 ("snv_106 ksh93 update breaks Install(1M)") has been fixed.
28*b30d1939SAndy Fiddaman#
29*b30d1939SAndy Fiddaman# Quote from CR #6800929:
3081af778eSCasper H.S. Dik# ---- snip ----
3181af778eSCasper H.S. Dik# so i just upgraded this morning from snv_105 to snv_106.  now
3281af778eSCasper H.S. Dik# Install(1M) is hanging whenever i run it.  i'm running it as follows:
3381af778eSCasper H.S. Dik#         Install -o debug -k i86xpv -T domu-219:/tmp
34*b30d1939SAndy Fiddaman#
3581af778eSCasper H.S. Dik# and here's where it's hung:
3681af778eSCasper H.S. Dik# ---8<---
37*b30d1939SAndy Fiddaman#  Edward Pilatowicz <edward.pilatowicz@sun.com>
3834f9b3eeSRoland Mainz# $ pstack 204600
3981af778eSCasper H.S. Dik# 204600: /bin/ksh /opt/onbld/bin/Install -o debug -k i86xpv -T domu-219:/tmp
4081af778eSCasper H.S. Dik#  fffffd7fff2e3d1a write    (1, 4154c0, 64)
4181af778eSCasper H.S. Dik#  fffffd7ffefdafc8 sfwr () + 2d0
4281af778eSCasper H.S. Dik#  fffffd7ffefc0f6f _sfflsbuf () + 217
4381af778eSCasper H.S. Dik#  fffffd7ffefcb9f7 sfsync () + 17f
4481af778eSCasper H.S. Dik#  fffffd7ffefc5c58 _sfphead () + 188
4581af778eSCasper H.S. Dik#  fffffd7ffefc5ef5 _sfpmove () + 55
4681af778eSCasper H.S. Dik#  fffffd7ffefc2595 _sfmode () + 22d
4781af778eSCasper H.S. Dik#  fffffd7ffefc5fb1 sfpool () + 99
4881af778eSCasper H.S. Dik#  fffffd7fff15eb8e sh_exec () + 2f56
4981af778eSCasper H.S. Dik#  fffffd7fff15f78c sh_exec () + 3b54
5081af778eSCasper H.S. Dik#  fffffd7fff15d9c8 sh_exec () + 1d90
5181af778eSCasper H.S. Dik#  fffffd7fff15788e sh_subshell () + 646
5281af778eSCasper H.S. Dik#  fffffd7fff134562 comsubst () + 8a2
5381af778eSCasper H.S. Dik#  fffffd7fff12f61f copyto () + bcf
5481af778eSCasper H.S. Dik#  fffffd7fff12df79 sh_macexpand () + 1f1
5581af778eSCasper H.S. Dik#  fffffd7fff1129f5 arg_expand () + a5
5681af778eSCasper H.S. Dik#  fffffd7fff112812 sh_argbuild () + 9a
5781af778eSCasper H.S. Dik#  fffffd7fff15dbe2 sh_exec () + 1faa
5881af778eSCasper H.S. Dik#  fffffd7fff15d854 sh_exec () + 1c1c
5981af778eSCasper H.S. Dik#  fffffd7fff0f22ef b_dot_cmd () + 507
6081af778eSCasper H.S. Dik#  fffffd7fff161559 sh_funct () + 199
6181af778eSCasper H.S. Dik#  fffffd7fff15ef35 sh_exec () + 32fd
6281af778eSCasper H.S. Dik#  fffffd7fff136e86 exfile () + 786
6381af778eSCasper H.S. Dik#  fffffd7fff136676 sh_main () + 7fe
6481af778eSCasper H.S. Dik#  0000000000400e72 main () + 52
6581af778eSCasper H.S. Dik#  0000000000400ccc ????
6681af778eSCasper H.S. Dik# ---8<---
67*b30d1939SAndy Fiddaman#
6881af778eSCasper H.S. Dik# there is only one place where Install(1M) invokes "uniq":
6981af778eSCasper H.S. Dik#         set -- `grep "^CONF" $modlist | sort | uniq`;
70*b30d1939SAndy Fiddaman#
7181af778eSCasper H.S. Dik# as it turns out, i can easily reproduce this problem as follows:
7281af778eSCasper H.S. Dik# ---8<---
7334f9b3eeSRoland Mainz# $ ksh93
7434f9b3eeSRoland Mainz# $ set -- `cat /etc/termcap | sort | uniq`
7581af778eSCasper H.S. Dik# <hang>
7681af778eSCasper H.S. Dik# ---8<---
7781af778eSCasper H.S. Dik# ---- snip ----
7881af778eSCasper H.S. Dik
7981af778eSCasper H.S. Dik
8034f9b3eeSRoland Mainz# test setup
8181af778eSCasper H.S. Dikfunction err_exit
8281af778eSCasper H.S. Dik{
8381af778eSCasper H.S. Dik	print -u2 -n "\t"
8481af778eSCasper H.S. Dik	print -u2 -r ${Command}[$1]: "${@:2}"
853e14f97fSRoger A. Faulkner	(( Errors < 127 && Errors++ ))
8681af778eSCasper H.S. Dik}
8781af778eSCasper H.S. Dikalias err_exit='err_exit $LINENO'
8881af778eSCasper H.S. Dik
8934f9b3eeSRoland Mainzset -o nounset
9034f9b3eeSRoland MainzCommand=${0##*/}
9181af778eSCasper H.S. Dikinteger Errors=0
9281af778eSCasper H.S. Dik
9334f9b3eeSRoland Mainz# common functions/variables
9434f9b3eeSRoland Mainzfunction isvalidpid
9534f9b3eeSRoland Mainz{
9634f9b3eeSRoland Mainz	kill -0 ${1} 2>/dev/null && return 0
9734f9b3eeSRoland Mainz	return 1
9834f9b3eeSRoland Mainz}
9934f9b3eeSRoland Mainzinteger testfilesize i maxwait
10081af778eSCasper H.S. Diktypeset tmpfile
10134f9b3eeSRoland Mainzinteger testid
10234f9b3eeSRoland Mainz
10381af778eSCasper H.S. Dik
10481af778eSCasper H.S. Dik# test 1: run loop and check various temp filesizes
1053e14f97fSRoger A. Faulknertmpfile="$(mktemp -t "sun_solaris_cr_6800929_large_command_substitution_hang.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file."
10681af778eSCasper H.S. Dik
10734f9b3eeSRoland Mainzcompound -a testcases=(
10834f9b3eeSRoland Mainz	# test 1a: Run test child for $(...)
10934f9b3eeSRoland Mainz	# (note the pipe chain has to end in a builtin command, an external command may not trigger the bug)
11034f9b3eeSRoland Mainz	( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
11134f9b3eeSRoland Mainz	# test 1b: Same as test1a but uses ${... ; } instead if $(...)
11234f9b3eeSRoland Mainz	( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
11334f9b3eeSRoland Mainz	# test 1c: Same as test1a but does not use a pipe
11434f9b3eeSRoland Mainz	( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
11534f9b3eeSRoland Mainz	# test 1d: Same as test1a but does not use a pipe
11634f9b3eeSRoland Mainz	( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
11734f9b3eeSRoland Mainz
11834f9b3eeSRoland Mainz	# test 1e: Same as test1a but uses an external "cat" command
11934f9b3eeSRoland Mainz	( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
12034f9b3eeSRoland Mainz	# test 1f: Same as test1a but uses an external "cat" command
12134f9b3eeSRoland Mainz	( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
12234f9b3eeSRoland Mainz	# test 1g: Same as test1a but uses an external "cat" command
12334f9b3eeSRoland Mainz	( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
12434f9b3eeSRoland Mainz	# test 1h: Same as test1a but uses an external "cat" command
12534f9b3eeSRoland Mainz	( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
12634f9b3eeSRoland Mainz)
12734f9b3eeSRoland Mainz
12834f9b3eeSRoland Mainzfor (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do
12981af778eSCasper H.S. Dik	# Create temp file
13081af778eSCasper H.S. Dik	{
13134f9b3eeSRoland Mainz		for (( i=0 ; i < testfilesize ; i+=64 )) ; do
13234f9b3eeSRoland Mainz			print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE"
13381af778eSCasper H.S. Dik		done
13481af778eSCasper H.S. Dik	} >"${tmpfile}"
13581af778eSCasper H.S. Dik
13681af778eSCasper H.S. Dik	# wait up to log2(i) seconds for the child to terminate
13781af778eSCasper H.S. Dik	# (this is 10 seconds for 1KB and 19 seconds for 512KB)
13834f9b3eeSRoland Mainz	(( maxwait=log2(testfilesize) ))
139*b30d1939SAndy Fiddaman
14034f9b3eeSRoland Mainz	for testid in "${!testcases[@]}" ; do
14134f9b3eeSRoland Mainz		nameref currtst=testcases[testid]
14234f9b3eeSRoland Mainz		${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
14334f9b3eeSRoland Mainz		(( childpid=$! ))
14434f9b3eeSRoland Mainz
14534f9b3eeSRoland Mainz		for (( i=0 ; i < maxwait ; i++ )) ; do
14634f9b3eeSRoland Mainz			isvalidpid ${childpid} || break
14734f9b3eeSRoland Mainz			sleep 0.25
14834f9b3eeSRoland Mainz		done
14934f9b3eeSRoland Mainz
15034f9b3eeSRoland Mainz		if isvalidpid ${childpid} ; then
15134f9b3eeSRoland Mainz			err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}."
15234f9b3eeSRoland Mainz			kill -KILL ${childpid} 2>/dev/null
15334f9b3eeSRoland Mainz		fi
15434f9b3eeSRoland Mainz		wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
15534f9b3eeSRoland Mainz
15634f9b3eeSRoland Mainz		# compare input/output
15734f9b3eeSRoland Mainz		cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}."
15834f9b3eeSRoland Mainz		rm "${tmpfile}.out"
15981af778eSCasper H.S. Dik	done
16081af778eSCasper H.S. Dik
16134f9b3eeSRoland Mainz	# Cleanup
16281af778eSCasper H.S. Dik	rm "${tmpfile}"
16381af778eSCasper H.S. Dikdone
16481af778eSCasper H.S. Dik
16581af778eSCasper H.S. Dik
16634f9b3eeSRoland Mainz# test 2a: Edward Pilatowicz <edward.pilatowicz@sun.com>'s Solaris-specific testcase
16734f9b3eeSRoland Mainz${SHELL} -o errexit -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null &
16881af778eSCasper H.S. Dik(( childpid=$! ))
16981af778eSCasper H.S. Diksleep 5
17034f9b3eeSRoland Mainzif isvalidpid ${childpid} ; then
17134f9b3eeSRoland Mainz	err_exit "test2a: child (pid=${childpid}) still busy."
17281af778eSCasper H.S. Dik	kill -KILL ${childpid} 2>/dev/null
17381af778eSCasper H.S. Dikfi
17434f9b3eeSRoland Mainzwait || err_exit "test2a: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
17534f9b3eeSRoland Mainz
17634f9b3eeSRoland Mainz
17734f9b3eeSRoland Mainz# test 2b: Same as test 2a but uses ${... ; } instead of $(...)
17834f9b3eeSRoland Mainz${SHELL} -o errexit -c 'builtin uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null &
17934f9b3eeSRoland Mainz(( childpid=$! ))
18034f9b3eeSRoland Mainzsleep 5
18134f9b3eeSRoland Mainzif isvalidpid ${childpid} ; then
18234f9b3eeSRoland Mainz	err_exit "test2b: child (pid=${childpid}) still busy."
18334f9b3eeSRoland Mainz	kill -KILL ${childpid} 2>/dev/null
18434f9b3eeSRoland Mainzfi
18534f9b3eeSRoland Mainzwait || err_exit "test2b: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
18634f9b3eeSRoland Mainz
18734f9b3eeSRoland Mainz
18834f9b3eeSRoland Mainz# test 2c: Same as test 2a but makes sure that "uniq" is not a builtin
18934f9b3eeSRoland Mainz${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null &
19034f9b3eeSRoland Mainz(( childpid=$! ))
19134f9b3eeSRoland Mainzsleep 5
19234f9b3eeSRoland Mainzif isvalidpid ${childpid} ; then
19334f9b3eeSRoland Mainz	err_exit "test2c: child (pid=${childpid}) still busy."
19434f9b3eeSRoland Mainz	kill -KILL ${childpid} 2>/dev/null
19534f9b3eeSRoland Mainzfi
19634f9b3eeSRoland Mainzwait || err_exit "test2c: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
19734f9b3eeSRoland Mainz
19834f9b3eeSRoland Mainz
19934f9b3eeSRoland Mainz# test 2d: Same as test 2c but uses ${... ; } instead of $(...)
20034f9b3eeSRoland Mainz${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null &
20134f9b3eeSRoland Mainz(( childpid=$! ))
20234f9b3eeSRoland Mainzsleep 5
20334f9b3eeSRoland Mainzif isvalidpid ${childpid} ; then
20434f9b3eeSRoland Mainz	err_exit "test2d: child (pid=${childpid}) still busy."
20534f9b3eeSRoland Mainz	kill -KILL ${childpid} 2>/dev/null
20634f9b3eeSRoland Mainzfi
20734f9b3eeSRoland Mainzwait || err_exit "test2d: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
20834f9b3eeSRoland Mainz
20981af778eSCasper H.S. Dik
21081af778eSCasper H.S. Dik# tests done
21181af778eSCasper H.S. Dikexit $((Errors))
212