1*01826a49SYabin Cui# source this file; set up for tests 2*01826a49SYabin Cui 3*01826a49SYabin Cui# Copyright (C) 2009-2016 Free Software Foundation, Inc. 4*01826a49SYabin Cui 5*01826a49SYabin Cui# This program is free software: you can redistribute it and/or modify 6*01826a49SYabin Cui# it under the terms of the GNU General Public License as published by 7*01826a49SYabin Cui# the Free Software Foundation, either version 3 of the License, or 8*01826a49SYabin Cui# (at your option) any later version. 9*01826a49SYabin Cui 10*01826a49SYabin Cui# This program is distributed in the hope that it will be useful, 11*01826a49SYabin Cui# but WITHOUT ANY WARRANTY; without even the implied warranty of 12*01826a49SYabin Cui# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*01826a49SYabin Cui# GNU General Public License for more details. 14*01826a49SYabin Cui 15*01826a49SYabin Cui# You should have received a copy of the GNU General Public License 16*01826a49SYabin Cui# along with this program. If not, see <https://www.gnu.org/licenses/>. 17*01826a49SYabin Cui 18*01826a49SYabin Cui# Using this file in a test 19*01826a49SYabin Cui# ========================= 20*01826a49SYabin Cui# 21*01826a49SYabin Cui# The typical skeleton of a test looks like this: 22*01826a49SYabin Cui# 23*01826a49SYabin Cui# #!/bin/sh 24*01826a49SYabin Cui# . "${srcdir=.}/init.sh"; path_prepend_ . 25*01826a49SYabin Cui# Execute some commands. 26*01826a49SYabin Cui# Note that these commands are executed in a subdirectory, therefore you 27*01826a49SYabin Cui# need to prepend "../" to relative filenames in the build directory. 28*01826a49SYabin Cui# Note that the "path_prepend_ ." is useful only if the body of your 29*01826a49SYabin Cui# test invokes programs residing in the initial directory. 30*01826a49SYabin Cui# For example, if the programs you want to test are in src/, and this test 31*01826a49SYabin Cui# script is named tests/test-1, then you would use "path_prepend_ ../src", 32*01826a49SYabin Cui# or perhaps export PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH" 33*01826a49SYabin Cui# to all tests via automake's TESTS_ENVIRONMENT. 34*01826a49SYabin Cui# Set the exit code 0 for success, 77 for skipped, or 1 or other for failure. 35*01826a49SYabin Cui# Use the skip_ and fail_ functions to print a diagnostic and then exit 36*01826a49SYabin Cui# with the corresponding exit code. 37*01826a49SYabin Cui# Exit $? 38*01826a49SYabin Cui 39*01826a49SYabin Cui# Executing a test that uses this file 40*01826a49SYabin Cui# ==================================== 41*01826a49SYabin Cui# 42*01826a49SYabin Cui# Running a single test: 43*01826a49SYabin Cui# $ make check TESTS=test-foo.sh 44*01826a49SYabin Cui# 45*01826a49SYabin Cui# Running a single test, with verbose output: 46*01826a49SYabin Cui# $ make check TESTS=test-foo.sh VERBOSE=yes 47*01826a49SYabin Cui# 48*01826a49SYabin Cui# Running a single test, with single-stepping: 49*01826a49SYabin Cui# 1. Go into a sub-shell: 50*01826a49SYabin Cui# $ bash 51*01826a49SYabin Cui# 2. Set relevant environment variables from TESTS_ENVIRONMENT in the 52*01826a49SYabin Cui# Makefile: 53*01826a49SYabin Cui# $ export srcdir=../../tests # this is an example 54*01826a49SYabin Cui# 3. Execute the commands from the test, copy&pasting them one by one: 55*01826a49SYabin Cui# $ . "$srcdir/init.sh"; path_prepend_ . 56*01826a49SYabin Cui# ... 57*01826a49SYabin Cui# 4. Finally 58*01826a49SYabin Cui# $ exit 59*01826a49SYabin Cui 60*01826a49SYabin CuiME_=`expr "./$0" : '.*/\(.*\)$'` 61*01826a49SYabin Cui 62*01826a49SYabin Cui# We use a trap below for cleanup. This requires us to go through 63*01826a49SYabin Cui# hoops to get the right exit status transported through the handler. 64*01826a49SYabin Cui# So use 'Exit STATUS' instead of 'exit STATUS' inside of the tests. 65*01826a49SYabin Cui# Turn off errexit here so that we don't trip the bug with OSF1/Tru64 66*01826a49SYabin Cui# sh inside this function. 67*01826a49SYabin CuiExit () { set +e; (exit $1); exit $1; } 68*01826a49SYabin Cui 69*01826a49SYabin Cui# Print warnings (e.g., about skipped and failed tests) to this file number. 70*01826a49SYabin Cui# Override by defining to say, 9, in init.cfg, and putting say, 71*01826a49SYabin Cui# export ...ENVVAR_SETTINGS...; $(SHELL) 9>&2 72*01826a49SYabin Cui# in the definition of TESTS_ENVIRONMENT in your tests/Makefile.am file. 73*01826a49SYabin Cui# This is useful when using automake's parallel tests mode, to print 74*01826a49SYabin Cui# the reason for skip/failure to console, rather than to the .log files. 75*01826a49SYabin Cui: ${stderr_fileno_=2} 76*01826a49SYabin Cui 77*01826a49SYabin Cui# Note that correct expansion of "$*" depends on IFS starting with ' '. 78*01826a49SYabin Cui# Always write the full diagnostic to stderr. 79*01826a49SYabin Cui# When stderr_fileno_ is not 2, also emit the first line of the 80*01826a49SYabin Cui# diagnostic to that file descriptor. 81*01826a49SYabin Cuiwarn_ () 82*01826a49SYabin Cui{ 83*01826a49SYabin Cui # If IFS does not start with ' ', set it and emit the warning in a subshell. 84*01826a49SYabin Cui case $IFS in 85*01826a49SYabin Cui ' '*) printf '%s\n' "$*" >&2 86*01826a49SYabin Cui test $stderr_fileno_ = 2 \ 87*01826a49SYabin Cui || { printf '%s\n' "$*" | sed 1q >&$stderr_fileno_ ; } ;; 88*01826a49SYabin Cui *) (IFS=' '; warn_ "$@");; 89*01826a49SYabin Cui esac 90*01826a49SYabin Cui} 91*01826a49SYabin Cuifail_ () { warn_ "$ME_: failed test: $@"; Exit 1; } 92*01826a49SYabin Cuiskip_ () { warn_ "$ME_: skipped test: $@"; Exit 77; } 93*01826a49SYabin Cuifatal_ () { warn_ "$ME_: hard error: $@"; Exit 99; } 94*01826a49SYabin Cuiframework_failure_ () { warn_ "$ME_: set-up failure: $@"; Exit 99; } 95*01826a49SYabin Cui 96*01826a49SYabin Cui# This is used to simplify checking of the return value 97*01826a49SYabin Cui# which is useful when ensuring a command fails as desired. 98*01826a49SYabin Cui# I.e., just doing `command ... &&fail=1` will not catch 99*01826a49SYabin Cui# a segfault in command for example. With this helper you 100*01826a49SYabin Cui# instead check an explicit exit code like 101*01826a49SYabin Cui# returns_ 1 command ... || fail 102*01826a49SYabin Cuireturns_ () { 103*01826a49SYabin Cui # Disable tracing so it doesn't interfere with stderr of the wrapped command 104*01826a49SYabin Cui { set +x; } 2>/dev/null 105*01826a49SYabin Cui 106*01826a49SYabin Cui local exp_exit="$1" 107*01826a49SYabin Cui shift 108*01826a49SYabin Cui "$@" 109*01826a49SYabin Cui test $? -eq $exp_exit && ret_=0 || ret_=1 110*01826a49SYabin Cui 111*01826a49SYabin Cui if test "$VERBOSE" = yes && test "$gl_set_x_corrupts_stderr_" = false; then 112*01826a49SYabin Cui set -x 113*01826a49SYabin Cui fi 114*01826a49SYabin Cui { return $ret_; } 2>/dev/null 115*01826a49SYabin Cui} 116*01826a49SYabin Cui 117*01826a49SYabin Cui# Sanitize this shell to POSIX mode, if possible. 118*01826a49SYabin CuiDUALCASE=1; export DUALCASE 119*01826a49SYabin Cuiif test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then 120*01826a49SYabin Cui emulate sh 121*01826a49SYabin Cui NULLCMD=: 122*01826a49SYabin Cui alias -g '${1+"$@"}'='"$@"' 123*01826a49SYabin Cui setopt NO_GLOB_SUBST 124*01826a49SYabin Cuielse 125*01826a49SYabin Cui case `(set -o) 2>/dev/null` in 126*01826a49SYabin Cui *posix*) set -o posix ;; 127*01826a49SYabin Cui esac 128*01826a49SYabin Cuifi 129*01826a49SYabin Cui 130*01826a49SYabin Cui# We require $(...) support unconditionally. 131*01826a49SYabin Cui# We require a few additional shell features only when $EXEEXT is nonempty, 132*01826a49SYabin Cui# in order to support automatic $EXEEXT emulation: 133*01826a49SYabin Cui# - hyphen-containing alias names 134*01826a49SYabin Cui# - we prefer to use ${var#...} substitution, rather than having 135*01826a49SYabin Cui# to work around lack of support for that feature. 136*01826a49SYabin Cui# The following code attempts to find a shell with support for these features. 137*01826a49SYabin Cui# If the current shell passes the test, we're done. Otherwise, test other 138*01826a49SYabin Cui# shells until we find one that passes. If one is found, re-exec it. 139*01826a49SYabin Cui# If no acceptable shell is found, skip the current test. 140*01826a49SYabin Cui# 141*01826a49SYabin Cui# The "...set -x; P=1 true 2>err..." test is to disqualify any shell that 142*01826a49SYabin Cui# emits "P=1" into err, as /bin/sh from SunOS 5.11 and OpenBSD 4.7 do. 143*01826a49SYabin Cui# 144*01826a49SYabin Cui# Use "9" to indicate success (rather than 0), in case some shell acts 145*01826a49SYabin Cui# like Solaris 10's /bin/sh but exits successfully instead of with status 2. 146*01826a49SYabin Cui 147*01826a49SYabin Cui# Eval this code in a subshell to determine a shell's suitability. 148*01826a49SYabin Cui# 10 - passes all tests; ok to use 149*01826a49SYabin Cui# 9 - ok, but enabling "set -x" corrupts app stderr; prefer higher score 150*01826a49SYabin Cui# ? - not ok 151*01826a49SYabin Cuigl_shell_test_script_=' 152*01826a49SYabin Cuitest $(echo y) = y || exit 1 153*01826a49SYabin Cuif_local_() { local v=1; }; f_local_ || exit 1 154*01826a49SYabin Cuiscore_=10 155*01826a49SYabin Cuiif test "$VERBOSE" = yes; then 156*01826a49SYabin Cui test -n "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" && score_=9 157*01826a49SYabin Cuifi 158*01826a49SYabin Cuitest -z "$EXEEXT" && exit $score_ 159*01826a49SYabin Cuishopt -s expand_aliases 160*01826a49SYabin Cuialias a-b="echo zoo" 161*01826a49SYabin Cuiv=abx 162*01826a49SYabin Cui test ${v%x} = ab \ 163*01826a49SYabin Cui && test ${v#a} = bx \ 164*01826a49SYabin Cui && test $(a-b) = zoo \ 165*01826a49SYabin Cui && exit $score_ 166*01826a49SYabin Cui' 167*01826a49SYabin Cui 168*01826a49SYabin Cuiif test "x$1" = "x--no-reexec"; then 169*01826a49SYabin Cui shift 170*01826a49SYabin Cuielse 171*01826a49SYabin Cui # Assume a working shell. Export to subshells (setup_ needs this). 172*01826a49SYabin Cui gl_set_x_corrupts_stderr_=false 173*01826a49SYabin Cui export gl_set_x_corrupts_stderr_ 174*01826a49SYabin Cui 175*01826a49SYabin Cui # Record the first marginally acceptable shell. 176*01826a49SYabin Cui marginal_= 177*01826a49SYabin Cui 178*01826a49SYabin Cui # Search for a shell that meets our requirements. 179*01826a49SYabin Cui for re_shell_ in __current__ "${CONFIG_SHELL:-no_shell}" \ 180*01826a49SYabin Cui /bin/sh bash dash zsh pdksh fail 181*01826a49SYabin Cui do 182*01826a49SYabin Cui test "$re_shell_" = no_shell && continue 183*01826a49SYabin Cui 184*01826a49SYabin Cui # If we've made it all the way to the sentinel, "fail" without 185*01826a49SYabin Cui # finding even a marginal shell, skip this test. 186*01826a49SYabin Cui if test "$re_shell_" = fail; then 187*01826a49SYabin Cui test -z "$marginal_" && skip_ failed to find an adequate shell 188*01826a49SYabin Cui re_shell_=$marginal_ 189*01826a49SYabin Cui break 190*01826a49SYabin Cui fi 191*01826a49SYabin Cui 192*01826a49SYabin Cui # When testing the current shell, simply "eval" the test code. 193*01826a49SYabin Cui # Otherwise, run it via $re_shell_ -c ... 194*01826a49SYabin Cui if test "$re_shell_" = __current__; then 195*01826a49SYabin Cui # 'eval'ing this code makes Solaris 10's /bin/sh exit with 196*01826a49SYabin Cui # $? set to 2. It does not evaluate any of the code after the 197*01826a49SYabin Cui # "unexpected" first '('. Thus, we must run it in a subshell. 198*01826a49SYabin Cui ( eval "$gl_shell_test_script_" ) > /dev/null 2>&1 199*01826a49SYabin Cui else 200*01826a49SYabin Cui "$re_shell_" -c "$gl_shell_test_script_" 2>/dev/null 201*01826a49SYabin Cui fi 202*01826a49SYabin Cui 203*01826a49SYabin Cui st_=$? 204*01826a49SYabin Cui 205*01826a49SYabin Cui # $re_shell_ works just fine. Use it. 206*01826a49SYabin Cui if test $st_ = 10; then 207*01826a49SYabin Cui gl_set_x_corrupts_stderr_=false 208*01826a49SYabin Cui break 209*01826a49SYabin Cui fi 210*01826a49SYabin Cui 211*01826a49SYabin Cui # If this is our first marginally acceptable shell, remember it. 212*01826a49SYabin Cui if test "$st_:$marginal_" = 9: ; then 213*01826a49SYabin Cui marginal_="$re_shell_" 214*01826a49SYabin Cui gl_set_x_corrupts_stderr_=true 215*01826a49SYabin Cui fi 216*01826a49SYabin Cui done 217*01826a49SYabin Cui 218*01826a49SYabin Cui if test "$re_shell_" != __current__; then 219*01826a49SYabin Cui # Found a usable shell. Preserve -v and -x. 220*01826a49SYabin Cui case $- in 221*01826a49SYabin Cui *v*x* | *x*v*) opts_=-vx ;; 222*01826a49SYabin Cui *v*) opts_=-v ;; 223*01826a49SYabin Cui *x*) opts_=-x ;; 224*01826a49SYabin Cui *) opts_= ;; 225*01826a49SYabin Cui esac 226*01826a49SYabin Cui re_shell=$re_shell_ 227*01826a49SYabin Cui export re_shell 228*01826a49SYabin Cui exec "$re_shell_" $opts_ "$0" --no-reexec "$@" 229*01826a49SYabin Cui echo "$ME_: exec failed" 1>&2 230*01826a49SYabin Cui exit 127 231*01826a49SYabin Cui fi 232*01826a49SYabin Cuifi 233*01826a49SYabin Cui 234*01826a49SYabin Cui# If this is bash, turn off all aliases. 235*01826a49SYabin Cuitest -n "$BASH_VERSION" && unalias -a 236*01826a49SYabin Cui 237*01826a49SYabin Cui# Note that when supporting $EXEEXT (transparently mapping from PROG_NAME to 238*01826a49SYabin Cui# PROG_NAME.exe), we want to support hyphen-containing names like test-acos. 239*01826a49SYabin Cui# That is part of the shell-selection test above. Why use aliases rather 240*01826a49SYabin Cui# than functions? Because support for hyphen-containing aliases is more 241*01826a49SYabin Cui# widespread than that for hyphen-containing function names. 242*01826a49SYabin Cuitest -n "$EXEEXT" && shopt -s expand_aliases 243*01826a49SYabin Cui 244*01826a49SYabin Cui# Enable glibc's malloc-perturbing option. 245*01826a49SYabin Cui# This is useful for exposing code that depends on the fact that 246*01826a49SYabin Cui# malloc-related functions often return memory that is mostly zeroed. 247*01826a49SYabin Cui# If you have the time and cycles, use valgrind to do an even better job. 248*01826a49SYabin Cui: ${MALLOC_PERTURB_=87} 249*01826a49SYabin Cuiexport MALLOC_PERTURB_ 250*01826a49SYabin Cui 251*01826a49SYabin Cui# This is a stub function that is run upon trap (upon regular exit and 252*01826a49SYabin Cui# interrupt). Override it with a per-test function, e.g., to unmount 253*01826a49SYabin Cui# a partition, or to undo any other global state changes. 254*01826a49SYabin Cuicleanup_ () { :; } 255*01826a49SYabin Cui 256*01826a49SYabin Cui# Emit a header similar to that from diff -u; Print the simulated "diff" 257*01826a49SYabin Cui# command so that the order of arguments is clear. Don't bother with @@ lines. 258*01826a49SYabin Cuiemit_diff_u_header_ () 259*01826a49SYabin Cui{ 260*01826a49SYabin Cui printf '%s\n' "diff -u $*" \ 261*01826a49SYabin Cui "--- $1 1970-01-01" \ 262*01826a49SYabin Cui "+++ $2 1970-01-01" 263*01826a49SYabin Cui} 264*01826a49SYabin Cui 265*01826a49SYabin Cui# Arrange not to let diff or cmp operate on /dev/null, 266*01826a49SYabin Cui# since on some systems (at least OSF/1 5.1), that doesn't work. 267*01826a49SYabin Cui# When there are not two arguments, or no argument is /dev/null, return 2. 268*01826a49SYabin Cui# When one argument is /dev/null and the other is not empty, 269*01826a49SYabin Cui# cat the nonempty file to stderr and return 1. 270*01826a49SYabin Cui# Otherwise, return 0. 271*01826a49SYabin Cuicompare_dev_null_ () 272*01826a49SYabin Cui{ 273*01826a49SYabin Cui test $# = 2 || return 2 274*01826a49SYabin Cui 275*01826a49SYabin Cui if test "x$1" = x/dev/null; then 276*01826a49SYabin Cui test -s "$2" || return 0 277*01826a49SYabin Cui emit_diff_u_header_ "$@"; sed 's/^/+/' "$2" 278*01826a49SYabin Cui return 1 279*01826a49SYabin Cui fi 280*01826a49SYabin Cui 281*01826a49SYabin Cui if test "x$2" = x/dev/null; then 282*01826a49SYabin Cui test -s "$1" || return 0 283*01826a49SYabin Cui emit_diff_u_header_ "$@"; sed 's/^/-/' "$1" 284*01826a49SYabin Cui return 1 285*01826a49SYabin Cui fi 286*01826a49SYabin Cui 287*01826a49SYabin Cui return 2 288*01826a49SYabin Cui} 289*01826a49SYabin Cui 290*01826a49SYabin Cuiif diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \ 291*01826a49SYabin Cui && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then 292*01826a49SYabin Cui # diff accepts the -u option and does not (like AIX 7 'diff') produce an 293*01826a49SYabin Cui # extra space on column 1 of every content line. 294*01826a49SYabin Cui if test -z "$diff_out_"; then 295*01826a49SYabin Cui compare_ () { diff -u "$@"; } 296*01826a49SYabin Cui else 297*01826a49SYabin Cui compare_ () 298*01826a49SYabin Cui { 299*01826a49SYabin Cui if diff -u "$@" > diff.out; then 300*01826a49SYabin Cui # No differences were found, but Solaris 'diff' produces output 301*01826a49SYabin Cui # "No differences encountered". Hide this output. 302*01826a49SYabin Cui rm -f diff.out 303*01826a49SYabin Cui true 304*01826a49SYabin Cui else 305*01826a49SYabin Cui cat diff.out 306*01826a49SYabin Cui rm -f diff.out 307*01826a49SYabin Cui false 308*01826a49SYabin Cui fi 309*01826a49SYabin Cui } 310*01826a49SYabin Cui fi 311*01826a49SYabin Cuielif 312*01826a49SYabin Cui for diff_opt_ in -U3 -c '' no; do 313*01826a49SYabin Cui test "$diff_opt_" = no && break 314*01826a49SYabin Cui diff_out_=`exec 2>/dev/null; diff $diff_opt_ "$0" "$0" </dev/null` && break 315*01826a49SYabin Cui done 316*01826a49SYabin Cui test "$diff_opt_" != no 317*01826a49SYabin Cuithen 318*01826a49SYabin Cui if test -z "$diff_out_"; then 319*01826a49SYabin Cui compare_ () { diff $diff_opt_ "$@"; } 320*01826a49SYabin Cui else 321*01826a49SYabin Cui compare_ () 322*01826a49SYabin Cui { 323*01826a49SYabin Cui if diff $diff_opt_ "$@" > diff.out; then 324*01826a49SYabin Cui # No differences were found, but AIX and HP-UX 'diff' produce output 325*01826a49SYabin Cui # "No differences encountered" or "There are no differences between the 326*01826a49SYabin Cui # files.". Hide this output. 327*01826a49SYabin Cui rm -f diff.out 328*01826a49SYabin Cui true 329*01826a49SYabin Cui else 330*01826a49SYabin Cui cat diff.out 331*01826a49SYabin Cui rm -f diff.out 332*01826a49SYabin Cui false 333*01826a49SYabin Cui fi 334*01826a49SYabin Cui } 335*01826a49SYabin Cui fi 336*01826a49SYabin Cuielif cmp -s /dev/null /dev/null 2>/dev/null; then 337*01826a49SYabin Cui compare_ () { cmp -s "$@"; } 338*01826a49SYabin Cuielse 339*01826a49SYabin Cui compare_ () { cmp "$@"; } 340*01826a49SYabin Cuifi 341*01826a49SYabin Cui 342*01826a49SYabin Cui# Usage: compare EXPECTED ACTUAL 343*01826a49SYabin Cui# 344*01826a49SYabin Cui# Given compare_dev_null_'s preprocessing, defer to compare_ if 2 or more. 345*01826a49SYabin Cui# Otherwise, propagate $? to caller: any diffs have already been printed. 346*01826a49SYabin Cuicompare () 347*01826a49SYabin Cui{ 348*01826a49SYabin Cui # This looks like it can be factored to use a simple "case $?" 349*01826a49SYabin Cui # after unchecked compare_dev_null_ invocation, but that would 350*01826a49SYabin Cui # fail in a "set -e" environment. 351*01826a49SYabin Cui if compare_dev_null_ "$@"; then 352*01826a49SYabin Cui return 0 353*01826a49SYabin Cui else 354*01826a49SYabin Cui case $? in 355*01826a49SYabin Cui 1) return 1;; 356*01826a49SYabin Cui *) compare_ "$@";; 357*01826a49SYabin Cui esac 358*01826a49SYabin Cui fi 359*01826a49SYabin Cui} 360*01826a49SYabin Cui 361*01826a49SYabin Cui# An arbitrary prefix to help distinguish test directories. 362*01826a49SYabin Cuitestdir_prefix_ () { printf gt; } 363*01826a49SYabin Cui 364*01826a49SYabin Cui# Run the user-overridable cleanup_ function, remove the temporary 365*01826a49SYabin Cui# directory and exit with the incoming value of $?. 366*01826a49SYabin Cuiremove_tmp_ () 367*01826a49SYabin Cui{ 368*01826a49SYabin Cui __st=$? 369*01826a49SYabin Cui cleanup_ 370*01826a49SYabin Cui # cd out of the directory we're about to remove 371*01826a49SYabin Cui cd "$initial_cwd_" || cd / || cd /tmp 372*01826a49SYabin Cui chmod -R u+rwx "$test_dir_" 373*01826a49SYabin Cui # If removal fails and exit status was to be 0, then change it to 1. 374*01826a49SYabin Cui rm -rf "$test_dir_" || { test $__st = 0 && __st=1; } 375*01826a49SYabin Cui exit $__st 376*01826a49SYabin Cui} 377*01826a49SYabin Cui 378*01826a49SYabin Cui# Given a directory name, DIR, if every entry in it that matches *.exe 379*01826a49SYabin Cui# contains only the specified bytes (see the case stmt below), then print 380*01826a49SYabin Cui# a space-separated list of those names and return 0. Otherwise, don't 381*01826a49SYabin Cui# print anything and return 1. Naming constraints apply also to DIR. 382*01826a49SYabin Cuifind_exe_basenames_ () 383*01826a49SYabin Cui{ 384*01826a49SYabin Cui feb_dir_=$1 385*01826a49SYabin Cui feb_fail_=0 386*01826a49SYabin Cui feb_result_= 387*01826a49SYabin Cui feb_sp_= 388*01826a49SYabin Cui for feb_file_ in $feb_dir_/*.exe; do 389*01826a49SYabin Cui # If there was no *.exe file, or there existed a file named "*.exe" that 390*01826a49SYabin Cui # was deleted between the above glob expansion and the existence test 391*01826a49SYabin Cui # below, just skip it. 392*01826a49SYabin Cui test "x$feb_file_" = "x$feb_dir_/*.exe" && test ! -f "$feb_file_" \ 393*01826a49SYabin Cui && continue 394*01826a49SYabin Cui # Exempt [.exe, since we can't create a function by that name, yet 395*01826a49SYabin Cui # we can't invoke [ by PATH search anyways due to shell builtins. 396*01826a49SYabin Cui test "x$feb_file_" = "x$feb_dir_/[.exe" && continue 397*01826a49SYabin Cui case $feb_file_ in 398*01826a49SYabin Cui *[!-a-zA-Z/0-9_.+]*) feb_fail_=1; break;; 399*01826a49SYabin Cui *) # Remove leading file name components as well as the .exe suffix. 400*01826a49SYabin Cui feb_file_=${feb_file_##*/} 401*01826a49SYabin Cui feb_file_=${feb_file_%.exe} 402*01826a49SYabin Cui feb_result_="$feb_result_$feb_sp_$feb_file_";; 403*01826a49SYabin Cui esac 404*01826a49SYabin Cui feb_sp_=' ' 405*01826a49SYabin Cui done 406*01826a49SYabin Cui test $feb_fail_ = 0 && printf %s "$feb_result_" 407*01826a49SYabin Cui return $feb_fail_ 408*01826a49SYabin Cui} 409*01826a49SYabin Cui 410*01826a49SYabin Cui# Consider the files in directory, $1. 411*01826a49SYabin Cui# For each file name of the form PROG.exe, create an alias named 412*01826a49SYabin Cui# PROG that simply invokes PROG.exe, then return 0. If any selected 413*01826a49SYabin Cui# file name or the directory name, $1, contains an unexpected character, 414*01826a49SYabin Cui# define no alias and return 1. 415*01826a49SYabin Cuicreate_exe_shims_ () 416*01826a49SYabin Cui{ 417*01826a49SYabin Cui case $EXEEXT in 418*01826a49SYabin Cui '') return 0 ;; 419*01826a49SYabin Cui .exe) ;; 420*01826a49SYabin Cui *) echo "$0: unexpected \$EXEEXT value: $EXEEXT" 1>&2; return 1 ;; 421*01826a49SYabin Cui esac 422*01826a49SYabin Cui 423*01826a49SYabin Cui base_names_=`find_exe_basenames_ $1` \ 424*01826a49SYabin Cui || { echo "$0 (exe_shim): skipping directory: $1" 1>&2; return 0; } 425*01826a49SYabin Cui 426*01826a49SYabin Cui if test -n "$base_names_"; then 427*01826a49SYabin Cui for base_ in $base_names_; do 428*01826a49SYabin Cui alias "$base_"="$base_$EXEEXT" 429*01826a49SYabin Cui done 430*01826a49SYabin Cui fi 431*01826a49SYabin Cui 432*01826a49SYabin Cui return 0 433*01826a49SYabin Cui} 434*01826a49SYabin Cui 435*01826a49SYabin Cui# Use this function to prepend to PATH an absolute name for each 436*01826a49SYabin Cui# specified, possibly-$initial_cwd_-relative, directory. 437*01826a49SYabin Cuipath_prepend_ () 438*01826a49SYabin Cui{ 439*01826a49SYabin Cui while test $# != 0; do 440*01826a49SYabin Cui path_dir_=$1 441*01826a49SYabin Cui case $path_dir_ in 442*01826a49SYabin Cui '') fail_ "invalid path dir: '$1'";; 443*01826a49SYabin Cui /*) abs_path_dir_=$path_dir_;; 444*01826a49SYabin Cui *) abs_path_dir_=$initial_cwd_/$path_dir_;; 445*01826a49SYabin Cui esac 446*01826a49SYabin Cui case $abs_path_dir_ in 447*01826a49SYabin Cui *:*) fail_ "invalid path dir: '$abs_path_dir_'";; 448*01826a49SYabin Cui esac 449*01826a49SYabin Cui PATH="$abs_path_dir_:$PATH" 450*01826a49SYabin Cui 451*01826a49SYabin Cui # Create an alias, FOO, for each FOO.exe in this directory. 452*01826a49SYabin Cui create_exe_shims_ "$abs_path_dir_" \ 453*01826a49SYabin Cui || fail_ "something failed (above): $abs_path_dir_" 454*01826a49SYabin Cui shift 455*01826a49SYabin Cui done 456*01826a49SYabin Cui export PATH 457*01826a49SYabin Cui} 458*01826a49SYabin Cui 459*01826a49SYabin Cuisetup_ () 460*01826a49SYabin Cui{ 461*01826a49SYabin Cui if test "$VERBOSE" = yes; then 462*01826a49SYabin Cui # Test whether set -x may cause the selected shell to corrupt an 463*01826a49SYabin Cui # application's stderr. Many do, including zsh-4.3.10 and the /bin/sh 464*01826a49SYabin Cui # from SunOS 5.11, OpenBSD 4.7 and Irix 5.x and 6.5. 465*01826a49SYabin Cui # If enabling verbose output this way would cause trouble, simply 466*01826a49SYabin Cui # issue a warning and refrain. 467*01826a49SYabin Cui if $gl_set_x_corrupts_stderr_; then 468*01826a49SYabin Cui warn_ "using SHELL=$SHELL with 'set -x' corrupts stderr" 469*01826a49SYabin Cui else 470*01826a49SYabin Cui set -x 471*01826a49SYabin Cui fi 472*01826a49SYabin Cui fi 473*01826a49SYabin Cui 474*01826a49SYabin Cui initial_cwd_=$PWD 475*01826a49SYabin Cui 476*01826a49SYabin Cui pfx_=`testdir_prefix_` 477*01826a49SYabin Cui test_dir_=`mktempd_ "$initial_cwd_" "$pfx_-$ME_.XXXX"` \ 478*01826a49SYabin Cui || fail_ "failed to create temporary directory in $initial_cwd_" 479*01826a49SYabin Cui cd "$test_dir_" || fail_ "failed to cd to temporary directory" 480*01826a49SYabin Cui 481*01826a49SYabin Cui # As autoconf-generated configure scripts do, ensure that IFS 482*01826a49SYabin Cui # is defined initially, so that saving and restoring $IFS works. 483*01826a49SYabin Cui gl_init_sh_nl_=' 484*01826a49SYabin Cui' 485*01826a49SYabin Cui IFS=" "" $gl_init_sh_nl_" 486*01826a49SYabin Cui 487*01826a49SYabin Cui # This trap statement, along with a trap on 0 below, ensure that the 488*01826a49SYabin Cui # temporary directory, $test_dir_, is removed upon exit as well as 489*01826a49SYabin Cui # upon receipt of any of the listed signals. 490*01826a49SYabin Cui for sig_ in 1 2 3 13 15; do 491*01826a49SYabin Cui eval "trap 'Exit $(expr $sig_ + 128)' $sig_" 492*01826a49SYabin Cui done 493*01826a49SYabin Cui} 494*01826a49SYabin Cui 495*01826a49SYabin Cui# Create a temporary directory, much like mktemp -d does. 496*01826a49SYabin Cui# Written by Jim Meyering. 497*01826a49SYabin Cui# 498*01826a49SYabin Cui# Usage: mktempd_ /tmp phoey.XXXXXXXXXX 499*01826a49SYabin Cui# 500*01826a49SYabin Cui# First, try to use the mktemp program. 501*01826a49SYabin Cui# Failing that, we'll roll our own mktemp-like function: 502*01826a49SYabin Cui# - try to get random bytes from /dev/urandom 503*01826a49SYabin Cui# - failing that, generate output from a combination of quickly-varying 504*01826a49SYabin Cui# sources and gzip. Ignore non-varying gzip header, and extract 505*01826a49SYabin Cui# "random" bits from there. 506*01826a49SYabin Cui# - given those bits, map to file-name bytes using tr, and try to create 507*01826a49SYabin Cui# the desired directory. 508*01826a49SYabin Cui# - make only $MAX_TRIES_ attempts 509*01826a49SYabin Cui 510*01826a49SYabin Cui# Helper function. Print $N pseudo-random bytes from a-zA-Z0-9. 511*01826a49SYabin Cuirand_bytes_ () 512*01826a49SYabin Cui{ 513*01826a49SYabin Cui n_=$1 514*01826a49SYabin Cui 515*01826a49SYabin Cui # Maybe try openssl rand -base64 $n_prime_|tr '+/=\012' abcd first? 516*01826a49SYabin Cui # But if they have openssl, they probably have mktemp, too. 517*01826a49SYabin Cui 518*01826a49SYabin Cui chars_=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 519*01826a49SYabin Cui dev_rand_=/dev/urandom 520*01826a49SYabin Cui if test -r "$dev_rand_"; then 521*01826a49SYabin Cui # Note: 256-length($chars_) == 194; 3 copies of $chars_ is 186 + 8 = 194. 522*01826a49SYabin Cui dd ibs=$n_ count=1 if=$dev_rand_ 2>/dev/null \ 523*01826a49SYabin Cui | LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_ 524*01826a49SYabin Cui return 525*01826a49SYabin Cui fi 526*01826a49SYabin Cui 527*01826a49SYabin Cui n_plus_50_=`expr $n_ + 50` 528*01826a49SYabin Cui cmds_='date; date +%N; free; who -a; w; ps auxww; ps ef; netstat -n' 529*01826a49SYabin Cui data_=` (eval "$cmds_") 2>&1 | gzip ` 530*01826a49SYabin Cui 531*01826a49SYabin Cui # Ensure that $data_ has length at least 50+$n_ 532*01826a49SYabin Cui while :; do 533*01826a49SYabin Cui len_=`echo "$data_"|wc -c` 534*01826a49SYabin Cui test $n_plus_50_ -le $len_ && break; 535*01826a49SYabin Cui data_=` (echo "$data_"; eval "$cmds_") 2>&1 | gzip ` 536*01826a49SYabin Cui done 537*01826a49SYabin Cui 538*01826a49SYabin Cui echo "$data_" \ 539*01826a49SYabin Cui | dd bs=1 skip=50 count=$n_ 2>/dev/null \ 540*01826a49SYabin Cui | LC_ALL=C tr -c $chars_ 01234567$chars_$chars_$chars_ 541*01826a49SYabin Cui} 542*01826a49SYabin Cui 543*01826a49SYabin Cuimktempd_ () 544*01826a49SYabin Cui{ 545*01826a49SYabin Cui case $# in 546*01826a49SYabin Cui 2);; 547*01826a49SYabin Cui *) fail_ "Usage: mktempd_ DIR TEMPLATE";; 548*01826a49SYabin Cui esac 549*01826a49SYabin Cui 550*01826a49SYabin Cui destdir_=$1 551*01826a49SYabin Cui template_=$2 552*01826a49SYabin Cui 553*01826a49SYabin Cui MAX_TRIES_=4 554*01826a49SYabin Cui 555*01826a49SYabin Cui # Disallow any trailing slash on specified destdir: 556*01826a49SYabin Cui # it would subvert the post-mktemp "case"-based destdir test. 557*01826a49SYabin Cui case $destdir_ in 558*01826a49SYabin Cui / | //) destdir_slash_=$destdir;; 559*01826a49SYabin Cui */) fail_ "invalid destination dir: remove trailing slash(es)";; 560*01826a49SYabin Cui *) destdir_slash_=$destdir_/;; 561*01826a49SYabin Cui esac 562*01826a49SYabin Cui 563*01826a49SYabin Cui case $template_ in 564*01826a49SYabin Cui *XXXX) ;; 565*01826a49SYabin Cui *) fail_ \ 566*01826a49SYabin Cui "invalid template: $template_ (must have a suffix of at least 4 X's)";; 567*01826a49SYabin Cui esac 568*01826a49SYabin Cui 569*01826a49SYabin Cui # First, try to use mktemp. 570*01826a49SYabin Cui d=`unset TMPDIR; { mktemp -d -t -p "$destdir_" "$template_"; } 2>/dev/null` && 571*01826a49SYabin Cui 572*01826a49SYabin Cui # The resulting name must be in the specified directory. 573*01826a49SYabin Cui case $d in "$destdir_slash_"*) :;; *) false;; esac && 574*01826a49SYabin Cui 575*01826a49SYabin Cui # It must have created the directory. 576*01826a49SYabin Cui test -d "$d" && 577*01826a49SYabin Cui 578*01826a49SYabin Cui # It must have 0700 permissions. Handle sticky "S" bits. 579*01826a49SYabin Cui perms=`ls -dgo "$d" 2>/dev/null` && 580*01826a49SYabin Cui case $perms in drwx--[-S]---*) :;; *) false;; esac && { 581*01826a49SYabin Cui echo "$d" 582*01826a49SYabin Cui return 583*01826a49SYabin Cui } 584*01826a49SYabin Cui 585*01826a49SYabin Cui # If we reach this point, we'll have to create a directory manually. 586*01826a49SYabin Cui 587*01826a49SYabin Cui # Get a copy of the template without its suffix of X's. 588*01826a49SYabin Cui base_template_=`echo "$template_"|sed 's/XX*$//'` 589*01826a49SYabin Cui 590*01826a49SYabin Cui # Calculate how many X's we've just removed. 591*01826a49SYabin Cui template_length_=`echo "$template_" | wc -c` 592*01826a49SYabin Cui nx_=`echo "$base_template_" | wc -c` 593*01826a49SYabin Cui nx_=`expr $template_length_ - $nx_` 594*01826a49SYabin Cui 595*01826a49SYabin Cui err_= 596*01826a49SYabin Cui i_=1 597*01826a49SYabin Cui while :; do 598*01826a49SYabin Cui X_=`rand_bytes_ $nx_` 599*01826a49SYabin Cui candidate_dir_="$destdir_slash_$base_template_$X_" 600*01826a49SYabin Cui err_=`mkdir -m 0700 "$candidate_dir_" 2>&1` \ 601*01826a49SYabin Cui && { echo "$candidate_dir_"; return; } 602*01826a49SYabin Cui test $MAX_TRIES_ -le $i_ && break; 603*01826a49SYabin Cui i_=`expr $i_ + 1` 604*01826a49SYabin Cui done 605*01826a49SYabin Cui fail_ "$err_" 606*01826a49SYabin Cui} 607*01826a49SYabin Cui 608*01826a49SYabin Cui# If you want to override the testdir_prefix_ function, 609*01826a49SYabin Cui# or to add more utility functions, use this file. 610*01826a49SYabin Cuitest -f "$srcdir/init.cfg" \ 611*01826a49SYabin Cui && . "$srcdir/init.cfg" 612*01826a49SYabin Cui 613*01826a49SYabin Cuisetup_ "$@" 614*01826a49SYabin Cui# This trap is here, rather than in the setup_ function, because some 615*01826a49SYabin Cui# shells run the exit trap at shell function exit, rather than script exit. 616*01826a49SYabin Cuitrap remove_tmp_ 0 617