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