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# This test checks whether the EXIT trap is called correctly in subshells 28# 29# This was reported as CR #6907460 ("EXIT trap handlers are sometimes executed twice"): 30# ------------ snip ------------ 31# During SST testing of snv_128(RE) we found out that ksh93 executes EXIT 32# trap handlers twice under some circumstances. 33# 34# Here is a test script: 35# --- 36# #!/bin/ksh93 -x 37# 38# function A 39# { 40# set -x 41# trap "print TRAP A >>log" EXIT 42# print >&2 43# } 44# 45# function B 46# { 47# set -x 48# trap "print TRAP B >>log" EXIT 49# A 50# } 51# 52# rm -f log 53# x=$(B) 54# --- 55# 56# It produces the following output on snv_128: 57# --- 58# + rm -f log 59# + B 60# + trap 'print TRAP B >>log' EXIT 61# + A 62# + trap 'print TRAP A >>log' EXIT 63# + print 64# + + print TRAP A 65# 1>& 2 66# + 1>> log 67# + print TRAP B 68# 69# + 1>> log 70# + print TRAP A 71# + 1>> log 72# + print TRAP B 73# + 1>> log 74# + x='' 75# --- 76# 77# The log file then contains: 78# TRAP A 79# TRAP B 80# TRAP A 81# TRAP B 82# 83# However, the expected log would be: 84# TRAP A 85# TRAP B 86# 87# When the "x=$(B)" line is changed to "B", the log is correct: 88# TRAP A 89# TRAP B 90# ------------ snip ------------ 91# 92 93# test setup 94function err_exit 95{ 96 print -u2 -n "\t" 97 print -u2 -r ${Command}[$1]: "${@:2}" 98 (( Errors < 127 && Errors++ )) 99} 100alias err_exit='err_exit $LINENO' 101 102set -o nounset 103Command=${0##*/} 104integer Errors=0 105 106typeset ocwd 107typeset tmpdir 108typeset out 109 110# create temporary test directory 111ocwd="$PWD" 112tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6907460_EXIT_trap_handlers_are_sometimes_executed_twice.XXXXXXXX")" || err_exit "Cannot create temporary directory" 113 114cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } 115 116 117# run tests 118 119# test 1: Run test with some variations 120compound vari 121typeset testname 122 123for vari.shell_options in \ 124 "" \ 125 "-o xtrace" \ 126 "-o errexit" \ 127 "-o errexit -o xtrace" ; do 128 for vari.xtrace1 in \ 129 "" \ 130 "set -x" ; do 131 for vari.xtrace2 in \ 132 "" \ 133 "set -x" ; do 134 for vari.func_A_end in \ 135 "" \ 136 "print >&2" \ 137 "return 0" \ 138 "print >&2 ; return 0" ; do 139 for vari.subshell in \ 140 $'x=$(B)' \ 141 $'x=$( ( B ) )' \ 142 $'x=${ B ; }' \ 143 $'x=${ ( B ) ; }' \ 144 $'( x=$(B) )' \ 145 $'( x=$( ( B ) ) )' \ 146 $'( x=${ B ; } )' \ 147 $'( x=${ ( B ) ; } )' ; do 148 testname="$( printf "test |%#B|\n" vari )" 149 150cat >"testscript.sh" <<EOF 151 function A 152 { 153 ${vari.xtrace1} 154 trap "print TRAP A >>log" EXIT 155 ${vari.func_A_end} 156 } 157 158 function B 159 { 160 ${vari.xtrace2} 161 trap "print TRAP B >>log" EXIT 162 A 163 } 164 165 rm -f log 166 ${vari.subshell} 167EOF 168 ${SHELL} ${vari.shell_options} "testscript.sh" >/dev/null 2>&1 || err_exit "${testname}: Unexpected error code $?" 169 rm "testscript.sh" 170 171 if [[ -f "log" ]] ; then 172 out="$( < log )" 173 rm "log" 174 else 175 err_exit "${testname}: File 'log' not found." 176 fi 177 [[ "${out}" == $'TRAP A\nTRAP B' ]] || err_exit "${testname}: Expected \$'TRAP A\nTRAP B', got $(printf "%q\n" "${out}")" 178 done 179 done 180 done 181 done 182done 183 184 185 186# test 2: This is the unmodified test from the bugster bug report 187( 188cat <<EOF 189 function A 190 { 191 set -x 192 trap "print TRAP A >>log" EXIT 193 print >&2 194 } 195 196 function B 197 { 198 set -x 199 trap "print TRAP B >>log" EXIT 200 A 201 } 202 203 rm -f log 204 x=\$(B) 205EOF 206) | ${SHELL} >/dev/null 2>&1 || err_exit "Unexpected error code $?" 207 208if [[ -f "log" ]] ; then 209 out="$( < log )" 210 rm "log" 211else 212 err_exit "File 'log' not found." 213fi 214[[ "${out}" == $'TRAP A\nTRAP B' ]] || err_exit "Expected \$'TRAP A\nTRAP B', got $(printf "%q\n" "${out}")" 215 216 217cd "${ocwd}" 218rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". 219 220# tests done 221exit $((Errors)) 222