1*b30d1939SAndy Fiddaman#
2*b30d1939SAndy Fiddaman# CDDL HEADER START
3*b30d1939SAndy Fiddaman#
4*b30d1939SAndy Fiddaman# The contents of this file are subject to the terms of the
5*b30d1939SAndy Fiddaman# Common Development and Distribution License (the "License").
6*b30d1939SAndy Fiddaman# You may not use this file except in compliance with the License.
7*b30d1939SAndy Fiddaman#
8*b30d1939SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*b30d1939SAndy Fiddaman# or http://www.opensolaris.org/os/licensing.
10*b30d1939SAndy Fiddaman# See the License for the specific language governing permissions
11*b30d1939SAndy Fiddaman# and limitations under the License.
12*b30d1939SAndy Fiddaman#
13*b30d1939SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each
14*b30d1939SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*b30d1939SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the
16*b30d1939SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying
17*b30d1939SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner]
18*b30d1939SAndy Fiddaman#
19*b30d1939SAndy Fiddaman# CDDL HEADER END
20*b30d1939SAndy Fiddaman#
21*b30d1939SAndy Fiddaman
22*b30d1939SAndy Fiddaman#
23*b30d1939SAndy Fiddaman# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24*b30d1939SAndy Fiddaman#
25*b30d1939SAndy Fiddaman
26*b30d1939SAndy Fiddaman#
27*b30d1939SAndy Fiddaman# Test whether CR #6800929 ("snv_106 ksh93 update breaks Install(1M)") has been fixed.
28*b30d1939SAndy Fiddaman#
29*b30d1939SAndy Fiddaman# Quote from CR #6800929:
30*b30d1939SAndy Fiddaman# ---- snip ----
31*b30d1939SAndy Fiddaman# so i just upgraded this morning from snv_105 to snv_106.  now
32*b30d1939SAndy Fiddaman# Install(1M) is hanging whenever i run it.  i'm running it as follows:
33*b30d1939SAndy Fiddaman#         Install -o debug -k i86xpv -T domu-219:/tmp
34*b30d1939SAndy Fiddaman#
35*b30d1939SAndy Fiddaman# and here's where it's hung:
36*b30d1939SAndy Fiddaman# ---8<---
37*b30d1939SAndy Fiddaman#  Edward Pilatowicz <edward.pilatowicz@sun.com>
38*b30d1939SAndy Fiddaman# $ pstack 204600
39*b30d1939SAndy Fiddaman# 204600: /bin/ksh /opt/onbld/bin/Install -o debug -k i86xpv -T domu-219:/tmp
40*b30d1939SAndy Fiddaman#  fffffd7fff2e3d1a write    (1, 4154c0, 64)
41*b30d1939SAndy Fiddaman#  fffffd7ffefdafc8 sfwr () + 2d0
42*b30d1939SAndy Fiddaman#  fffffd7ffefc0f6f _sfflsbuf () + 217
43*b30d1939SAndy Fiddaman#  fffffd7ffefcb9f7 sfsync () + 17f
44*b30d1939SAndy Fiddaman#  fffffd7ffefc5c58 _sfphead () + 188
45*b30d1939SAndy Fiddaman#  fffffd7ffefc5ef5 _sfpmove () + 55
46*b30d1939SAndy Fiddaman#  fffffd7ffefc2595 _sfmode () + 22d
47*b30d1939SAndy Fiddaman#  fffffd7ffefc5fb1 sfpool () + 99
48*b30d1939SAndy Fiddaman#  fffffd7fff15eb8e sh_exec () + 2f56
49*b30d1939SAndy Fiddaman#  fffffd7fff15f78c sh_exec () + 3b54
50*b30d1939SAndy Fiddaman#  fffffd7fff15d9c8 sh_exec () + 1d90
51*b30d1939SAndy Fiddaman#  fffffd7fff15788e sh_subshell () + 646
52*b30d1939SAndy Fiddaman#  fffffd7fff134562 comsubst () + 8a2
53*b30d1939SAndy Fiddaman#  fffffd7fff12f61f copyto () + bcf
54*b30d1939SAndy Fiddaman#  fffffd7fff12df79 sh_macexpand () + 1f1
55*b30d1939SAndy Fiddaman#  fffffd7fff1129f5 arg_expand () + a5
56*b30d1939SAndy Fiddaman#  fffffd7fff112812 sh_argbuild () + 9a
57*b30d1939SAndy Fiddaman#  fffffd7fff15dbe2 sh_exec () + 1faa
58*b30d1939SAndy Fiddaman#  fffffd7fff15d854 sh_exec () + 1c1c
59*b30d1939SAndy Fiddaman#  fffffd7fff0f22ef b_dot_cmd () + 507
60*b30d1939SAndy Fiddaman#  fffffd7fff161559 sh_funct () + 199
61*b30d1939SAndy Fiddaman#  fffffd7fff15ef35 sh_exec () + 32fd
62*b30d1939SAndy Fiddaman#  fffffd7fff136e86 exfile () + 786
63*b30d1939SAndy Fiddaman#  fffffd7fff136676 sh_main () + 7fe
64*b30d1939SAndy Fiddaman#  0000000000400e72 main () + 52
65*b30d1939SAndy Fiddaman#  0000000000400ccc ????
66*b30d1939SAndy Fiddaman# ---8<---
67*b30d1939SAndy Fiddaman#
68*b30d1939SAndy Fiddaman# there is only one place where Install(1M) invokes "uniq":
69*b30d1939SAndy Fiddaman#         set -- `grep "^CONF" $modlist | sort | uniq`;
70*b30d1939SAndy Fiddaman#
71*b30d1939SAndy Fiddaman# as it turns out, i can easily reproduce this problem as follows:
72*b30d1939SAndy Fiddaman# ---8<---
73*b30d1939SAndy Fiddaman# $ ksh93
74*b30d1939SAndy Fiddaman# $ set -- `cat /etc/termcap | sort | uniq`
75*b30d1939SAndy Fiddaman# <hang>
76*b30d1939SAndy Fiddaman# ---8<---
77*b30d1939SAndy Fiddaman# ---- snip ----
78*b30d1939SAndy Fiddaman
79*b30d1939SAndy Fiddaman
80*b30d1939SAndy Fiddaman# test setup
81*b30d1939SAndy Fiddamanfunction err_exit
82*b30d1939SAndy Fiddaman{
83*b30d1939SAndy Fiddaman	print -u2 -n "\t"
84*b30d1939SAndy Fiddaman	print -u2 -r ${Command}[$1]: "${@:2}"
85*b30d1939SAndy Fiddaman	(( Errors < 127 && Errors++ ))
86*b30d1939SAndy Fiddaman}
87*b30d1939SAndy Fiddamanalias err_exit='err_exit $LINENO'
88*b30d1939SAndy Fiddaman
89*b30d1939SAndy Fiddamanset -o nounset
90*b30d1939SAndy FiddamanCommand=${0##*/}
91*b30d1939SAndy Fiddamaninteger Errors=0
92*b30d1939SAndy Fiddaman
93*b30d1939SAndy Fiddaman# common functions/variables
94*b30d1939SAndy Fiddamanfunction isvalidpid
95*b30d1939SAndy Fiddaman{
96*b30d1939SAndy Fiddaman	kill -0 ${1} 2>/dev/null && return 0
97*b30d1939SAndy Fiddaman	return 1
98*b30d1939SAndy Fiddaman}
99*b30d1939SAndy Fiddamaninteger testfilesize i maxwait
100*b30d1939SAndy Fiddamantypeset tmpfile
101*b30d1939SAndy Fiddamaninteger testid
102*b30d1939SAndy Fiddaman
103*b30d1939SAndy Fiddaman
104*b30d1939SAndy Fiddaman# test 1: run loop and check various temp filesizes
105*b30d1939SAndy Fiddamantmpfile="$(mktemp -t "sun_solaris_cr_6800929_large_command_substitution_hang.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file."
106*b30d1939SAndy Fiddaman
107*b30d1939SAndy Fiddamancompound -a testcases=(
108*b30d1939SAndy Fiddaman	# test 1a: Run test child for $(...)
109*b30d1939SAndy Fiddaman	# (note the pipe chain has to end in a builtin command, an external command may not trigger the bug)
110*b30d1939SAndy Fiddaman	( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
111*b30d1939SAndy Fiddaman	# test 1b: Same as test1a but uses ${... ; } instead if $(...)
112*b30d1939SAndy Fiddaman	( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
113*b30d1939SAndy Fiddaman	# test 1c: Same as test1a but does not use a pipe
114*b30d1939SAndy Fiddaman	( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
115*b30d1939SAndy Fiddaman	# test 1d: Same as test1a but does not use a pipe
116*b30d1939SAndy Fiddaman	( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
117*b30d1939SAndy Fiddaman
118*b30d1939SAndy Fiddaman	# test 1e: Same as test1a but uses an external "cat" command
119*b30d1939SAndy Fiddaman	( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )
120*b30d1939SAndy Fiddaman	# test 1f: Same as test1a but uses an external "cat" command
121*b30d1939SAndy Fiddaman	( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )
122*b30d1939SAndy Fiddaman	# test 1g: Same as test1a but uses an external "cat" command
123*b30d1939SAndy Fiddaman	( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )
124*b30d1939SAndy Fiddaman	# test 1h: Same as test1a but uses an external "cat" command
125*b30d1939SAndy Fiddaman	( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )
126*b30d1939SAndy Fiddaman)
127*b30d1939SAndy Fiddaman
128*b30d1939SAndy Fiddamanfor (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do
129*b30d1939SAndy Fiddaman	# Create temp file
130*b30d1939SAndy Fiddaman	{
131*b30d1939SAndy Fiddaman		for (( i=0 ; i < testfilesize ; i+=64 )) ; do
132*b30d1939SAndy Fiddaman			print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE"
133*b30d1939SAndy Fiddaman		done
134*b30d1939SAndy Fiddaman	} >"${tmpfile}"
135*b30d1939SAndy Fiddaman
136*b30d1939SAndy Fiddaman	# wait up to log2(i) seconds for the child to terminate
137*b30d1939SAndy Fiddaman	# (this is 10 seconds for 1KB and 19 seconds for 512KB)
138*b30d1939SAndy Fiddaman	(( maxwait=log2(testfilesize) ))
139*b30d1939SAndy Fiddaman
140*b30d1939SAndy Fiddaman	for testid in "${!testcases[@]}" ; do
141*b30d1939SAndy Fiddaman		nameref currtst=testcases[testid]
142*b30d1939SAndy Fiddaman		${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &
143*b30d1939SAndy Fiddaman		(( childpid=$! ))
144*b30d1939SAndy Fiddaman
145*b30d1939SAndy Fiddaman		for (( i=0 ; i < maxwait ; i++ )) ; do
146*b30d1939SAndy Fiddaman			isvalidpid ${childpid} || break
147*b30d1939SAndy Fiddaman			sleep 0.25
148*b30d1939SAndy Fiddaman		done
149*b30d1939SAndy Fiddaman
150*b30d1939SAndy Fiddaman		if isvalidpid ${childpid} ; then
151*b30d1939SAndy Fiddaman			err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}."
152*b30d1939SAndy Fiddaman			kill -KILL ${childpid} 2>/dev/null
153*b30d1939SAndy Fiddaman		fi
154*b30d1939SAndy Fiddaman		wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
155*b30d1939SAndy Fiddaman
156*b30d1939SAndy Fiddaman		# compare input/output
157*b30d1939SAndy Fiddaman		cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}."
158*b30d1939SAndy Fiddaman		rm "${tmpfile}.out"
159*b30d1939SAndy Fiddaman	done
160*b30d1939SAndy Fiddaman
161*b30d1939SAndy Fiddaman	# Cleanup
162*b30d1939SAndy Fiddaman	rm "${tmpfile}"
163*b30d1939SAndy Fiddamandone
164*b30d1939SAndy Fiddaman
165*b30d1939SAndy Fiddaman
166*b30d1939SAndy Fiddaman# test 2a: Edward Pilatowicz <edward.pilatowicz@sun.com>'s Solaris-specific testcase
167*b30d1939SAndy Fiddaman${SHELL} -o errexit -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null &
168*b30d1939SAndy Fiddaman(( childpid=$! ))
169*b30d1939SAndy Fiddamansleep 5
170*b30d1939SAndy Fiddamanif isvalidpid ${childpid} ; then
171*b30d1939SAndy Fiddaman	err_exit "test2a: child (pid=${childpid}) still busy."
172*b30d1939SAndy Fiddaman	kill -KILL ${childpid} 2>/dev/null
173*b30d1939SAndy Fiddamanfi
174*b30d1939SAndy Fiddamanwait || err_exit "test2a: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
175*b30d1939SAndy Fiddaman
176*b30d1939SAndy Fiddaman
177*b30d1939SAndy Fiddaman# test 2b: Same as test 2a but uses ${... ; } instead of $(...)
178*b30d1939SAndy Fiddaman${SHELL} -o errexit -c 'builtin uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null &
179*b30d1939SAndy Fiddaman(( childpid=$! ))
180*b30d1939SAndy Fiddamansleep 5
181*b30d1939SAndy Fiddamanif isvalidpid ${childpid} ; then
182*b30d1939SAndy Fiddaman	err_exit "test2b: child (pid=${childpid}) still busy."
183*b30d1939SAndy Fiddaman	kill -KILL ${childpid} 2>/dev/null
184*b30d1939SAndy Fiddamanfi
185*b30d1939SAndy Fiddamanwait || err_exit "test2b: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
186*b30d1939SAndy Fiddaman
187*b30d1939SAndy Fiddaman
188*b30d1939SAndy Fiddaman# test 2c: Same as test 2a but makes sure that "uniq" is not a builtin
189*b30d1939SAndy Fiddaman${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null &
190*b30d1939SAndy Fiddaman(( childpid=$! ))
191*b30d1939SAndy Fiddamansleep 5
192*b30d1939SAndy Fiddamanif isvalidpid ${childpid} ; then
193*b30d1939SAndy Fiddaman	err_exit "test2c: child (pid=${childpid}) still busy."
194*b30d1939SAndy Fiddaman	kill -KILL ${childpid} 2>/dev/null
195*b30d1939SAndy Fiddamanfi
196*b30d1939SAndy Fiddamanwait || err_exit "test2c: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
197*b30d1939SAndy Fiddaman
198*b30d1939SAndy Fiddaman
199*b30d1939SAndy Fiddaman# test 2d: Same as test 2c but uses ${... ; } instead of $(...)
200*b30d1939SAndy Fiddaman${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null &
201*b30d1939SAndy Fiddaman(( childpid=$! ))
202*b30d1939SAndy Fiddamansleep 5
203*b30d1939SAndy Fiddamanif isvalidpid ${childpid} ; then
204*b30d1939SAndy Fiddaman	err_exit "test2d: child (pid=${childpid}) still busy."
205*b30d1939SAndy Fiddaman	kill -KILL ${childpid} 2>/dev/null
206*b30d1939SAndy Fiddamanfi
207*b30d1939SAndy Fiddamanwait || err_exit "test2d: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)
208*b30d1939SAndy Fiddaman
209*b30d1939SAndy Fiddaman
210*b30d1939SAndy Fiddaman# tests done
211*b30d1939SAndy Fiddamanexit $((Errors))
212