init.sh: penalize a set-x-impaired shell; don't disqualify it
authorJim Meyering <meyering@redhat.com>
Wed, 8 Sep 2010 20:24:22 +0000 (22:24 +0200)
committerJim Meyering <meyering@redhat.com>
Thu, 9 Sep 2010 08:44:28 +0000 (10:44 +0200)
* tests/init.sh: Too many shells corrupt application stderr when
you set -x, so we can't afford to disqualify them, since at least
on Irix-6.5, that would disqualify all bourne shells.
Instead, use a more discerning approach.
When iterating through candidate shells, give each a score
of 10 for perfect, 9 if corrupts stderr upon set -x but passes
all other tests, and some other value if it is unacceptable.
Use the first shell that gets a score of 10.
If no shell scores 10, use the first that scored 9.
Finally, when VERBOSE=yes is requested and set -x might cause trouble, simply
issue a warning and refrain from enabling debug output.

ChangeLog
tests/init.sh

index 82937ac..2ac4e00 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-09-08  Jim Meyering  <meyering@redhat.com>
+
+       init.sh: penalize a set-x-impaired shell; don't disqualify it
+       * tests/init.sh: Too many shells corrupt application stderr when
+       you set -x, so we can't afford to disqualify them, since at least
+       on Irix-6.5, that would disqualify all bourne shells.
+       Instead, use a two-pass approach.
+       On the first pass, try to find a shell that meets the stricter
+       condition that set -x does not corrupt stderr.
+       If no shell meets the stricter condition, retest each candidate
+       shell, but without that extra condition.  Finally, when
+       VERBOSE=yes is requested and set -x might cause trouble, simply
+       issue a warning and refrain from enabling debug output.
+
 2010-09-08  Eric Blake  <eblake@redhat.com>
 
        unsetenv: fix OpenBSD bug
index 9886a8d..c5d1961 100644 (file)
@@ -109,48 +109,84 @@ fi
 # Use "9" to indicate success (rather than 0), in case some shell acts
 # like Solaris 10's /bin/sh but exits successfully instead of with status 2.
 
+# Eval this code in a subshell to determine a shell's suitability.
+# 10 - passes all tests; ok to use
+#  9 - ok, but enabling "set -x" corrupts application stderr; prefer higher score
+#  ? - not ok
 gl_shell_test_script_='
 test $(echo y) = y || exit 1
-test -z "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" || exit 1
-test -z "$EXEEXT" && exit 9
+score_=10
+if test "$VERBOSE" = yes; then
+  test -n "$( (exec 3>&1; set -x; P=1 true 2>&3) 2> /dev/null)" && score_=9
+fi
+test -z "$EXEEXT" && exit $score_
 shopt -s expand_aliases
 alias a-b="echo zoo"
 v=abx
      test ${v%x} = ab \
   && test ${v#a} = bx \
   && test $(a-b) = zoo \
-  && exit 9
+  && exit $score_
 '
 
 if test "x$1" = "x--no-reexec"; then
   shift
 else
-  # 'eval'ing the above code makes Solaris 10's /bin/sh exit with $? set to 2.
-  # It does not evaluate any of the code after the "unexpected" `('.  Thus,
-  # we must run it in a subshell.
-  ( eval "$gl_shell_test_script_" ) > /dev/null 2>&1
-  if test $? = 9; then
-    : # The current shell is adequate.  No re-exec required.
-  else
-    # Search for a shell that meets our requirements.
-    for re_shell_ in "${CONFIG_SHELL:-no_shell}" /bin/sh bash dash zsh pdksh fail
-    do
-      test "$re_shell_" = no_shell && continue
-      test "$re_shell_" = fail && skip_ failed to find an adequate shell
+  # Assume a working shell.  Export to subshells (setup_ needs this).
+  gl_set_x_corrupts_stderr_=false
+  export gl_set_x_corrupts_stderr_
+
+  # Record the first marginally acceptable shell.
+  marginal_=
+
+  # Search for a shell that meets our requirements.
+  for re_shell_ in __current__ "${CONFIG_SHELL:-no_shell}" \
+      /bin/sh bash dash zsh pdksh fail
+  do
+    test "$re_shell_" = no_shell && continue
+
+    # If we've made it all the way to the sentinel, "fail" without
+    # finding even a marginal shell, skip this test.
+    if test "$re_shell_" = fail; then
+      test -z "$marginal_" && skip_ failed to find an adequate shell
+      re_shell_=$marginal_
+      break
+    fi
+
+    # When testing the current shell, simply "eval" the test code.
+    # Otherwise, run it via $re_shell_ -c ...
+    if test "$re_shell_" = __current__; then
+      # 'eval'ing this code makes Solaris 10's /bin/sh exit with
+      # $? set to 2.  It does not evaluate any of the code after the
+      # "unexpected" first `('.  Thus, we must run it in a subshell.
+      ( eval "$gl_shell_test_script_" ) > /dev/null 2>&1
+    else
       "$re_shell_" -c "$gl_shell_test_script_" 2>/dev/null
-      if test $? = 9; then
-        # Found an acceptable shell.  Preserve -v and -x.
-        case $- in
-          *v*x* | *x*v*) opts_=-vx ;;
-          *v*) opts_=-v ;;
-          *x*) opts_=-x ;;
-          *) opts_= ;;
-        esac
-        exec "$re_shell_" $opts_ "$0" --no-reexec "$@"
-        echo "$ME_: exec failed" 1>&2
-        exit 127
-      fi
-    done
+    fi
+
+    st_=$?
+
+    # $re_shell_ works just fine.  Use it.
+    test $st_ = 10 && break
+
+    # If this is our first marginally acceptable shell, remember it.
+    if test "$st_:$marginal_" = 9: ; then
+      marginal_="$re_shell_"
+      gl_set_x_corrupts_stderr_=true
+    fi
+  done
+
+  if test "$re_shell_" != __current__; then
+    # Found a usable shell.  Preserve -v and -x.
+    case $- in
+      *v*x* | *x*v*) opts_=-vx ;;
+      *v*) opts_=-v ;;
+      *x*) opts_=-x ;;
+      *) opts_= ;;
+    esac
+    exec "$re_shell_" $opts_ "$0" --no-reexec "$@"
+    echo "$ME_: exec failed" 1>&2
+    exit 127
   fi
 fi
 
@@ -269,7 +305,18 @@ path_prepend_()
 
 setup_()
 {
-  test "$VERBOSE" = yes && set -x
+  if test "$VERBOSE" = yes; then
+    # Test whether set -x may cause the selected shell to corrupt an
+    # application's stderr.  Many do, including zsh-4.3.10 and the /bin/sh
+    # from SunOS 5.11, OpenBSD 4.7 and Irix 5.x and 6.5.
+    # If enabling verbose output this way would cause trouble, simply
+    # issue a warning and refrain.
+    if $gl_set_x_corrupts_stderr_; then
+      warn_ "using SHELL=$SHELL with 'set -x' corrupts stderr"
+    else
+      set -x
+    fi
+  fi
 
   initial_cwd_=$PWD