changeset 12881:c6e9c683bc41

Really work around around "broken pipe" error message from bash 3.2.
author Bruno Haible <bruno@clisp.org>
date Sun, 21 Feb 2010 13:27:25 +0100
parents 0ca4a77ffffb
children 4c2d2e457224
files ChangeLog gnulib-tool
diffstat 2 files changed, 38 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-02-21  Bruno Haible  <bruno@clisp.org>
+
+	Really work around around "broken pipe" error message from bash 3.2.
+	* gnulib-tool (func_reset_sigpipe): Remove function.
+	(echo): In bash 3.2, define to a function that uses printf.
+	Analyzed by Ralf Wildenhues, Chet Ramey, Ben Pfaff.
+
 2010-02-20  Bruno Haible  <bruno@clisp.org>
 
 	Restore support for automake 1.9.6 with autoconf 2.61.
--- a/gnulib-tool
+++ b/gnulib-tool
@@ -661,39 +661,20 @@
   fi
 }
 
-# func_reset_sigpipe
-# Resets SIGPIPE to its default behaviour. SIGPIPE is signalled when a process
-# writes into a pipe with no readers, i.e. a pipe where all readers have
-# already closed their file descriptor that read from it or exited entirely.
-# The default behaviour is to terminate the current process without an error
-# message.
-# When "trap '' SIGPIPE" is in effect, the behaviour (at least with bash) is to
-# terminate the current process with an error message.
-# This function should be called at the beginning of a command that only
-# produces output to stdout (i.e. no side effects!), when the command that
-# will read from this pipe might prematurely exit or close its standard input
-# descriptor.
-if test -n "$BASH_VERSION"; then
-  # The problem has only been reported with bash. Probably it occurs only with
-  # bash-3.2. For the reasons, see
-  # <http://lists.gnu.org/archive/html/bug-bash/2008-12/msg00050.html>.
-  # Note that Solaris sh does not understand "trap - SIGPIPE".
-  func_reset_sigpipe ()
-  {
-    trap - SIGPIPE
-  }
-else
-  func_reset_sigpipe ()
-  {
-    :
-  }
-fi
-
-# Ensure an 'echo' command that does not interpret backslashes.
-# Test cases:
+# Ensure an 'echo' command
+#   1. does not interpret backslashes and
+#   2. does not print an error message "broken pipe" when writing into a pipe
+#      with no writers.
+#
+# Test cases for problem 1:
 #   echo '\n' | wc -l                 prints 1 when OK, 2 when KO
 #   echo '\t' | grep t > /dev/null    has return code 0 when OK, 1 when KO
-# This problem is a weird heritage from SVR4. BSD got it right (except that
+# Test cases for problem 2:
+#   echo hi | true                    frequently prints
+#                                     "bash: echo: write error: Broken pipe"
+#                                     to standard error in bash 3.2.
+#
+# Problem 1 is a weird heritage from SVR4. BSD got it right (except that
 # BSD echo interprets '-n' as an option, which is also not desirable).
 # Nowadays the problem occurs in 4 situations:
 # - in bash, when the shell option xpg_echo is set (bash >= 2.04)
@@ -716,6 +697,12 @@
 # - otherwise: respawn using /bin/sh and rely on the workarounds.
 # When respawning, we pass --no-reexec as first argument, so as to avoid
 # turning this script into a fork bomb in unlucky situations.
+#
+# Problem 2 is specific to bash 3.2 and affects the 'echo' built-in, but not
+# the 'printf' built-in. See
+#   <http://lists.gnu.org/archive/html/bug-bash/2008-12/msg00050.html>
+#   <http://lists.gnu.org/archive/html/bug-gnulib/2010-02/msg00154.html>
+# The workaround is: define echo to a function that uses the printf built-in.
 have_echo=
 if echo '\t' | grep t > /dev/null; then
   have_echo=yes # Lucky!
@@ -823,6 +810,15 @@
   exec /bin/sh "$0" --no-reexec "$@"
   exit 127
 fi
+# Now handle problem 2, specific to bash 3.2.
+case "$BASH_VERSION" in
+  3.2*)
+    echo ()
+    {
+      printf '%s\n' "$*"
+    }
+    ;;
+esac
 if test -z "$have_echo"; then
   func_fatal_error "Shell does not support 'echo' correctly. Please install GNU bash and set the environment variable CONFIG_SHELL to point to it."
 fi
@@ -2029,8 +2025,7 @@
       func_filter_filelist lib_files "$nl" "$all_files" 'lib/' '' 'lib/' ''
       # Remove $already_mentioned_files from $lib_files.
       echo "$lib_files" | LC_ALL=C sort -u > "$tmp"/lib-files
-      extra_files=`func_reset_sigpipe; \
-                   for f in $already_mentioned_files; do echo $f; done \
+      extra_files=`for f in $already_mentioned_files; do echo $f; done \
                    | LC_ALL=C sort -u | LC_ALL=C join -v 2 - "$tmp"/lib-files`
       if test -n "$extra_files"; then
         echo "EXTRA_DIST +=" $extra_files
@@ -2266,7 +2261,7 @@
     handledmodules=`for m in $handledmodules $inmodules_this_round; do echo $m; done | LC_ALL=C sort -u`
     # Remove $handledmodules from $inmodules.
     for m in $inmodules; do echo $m; done | LC_ALL=C sort -u > "$tmp"/queued-modules
-    inmodules=`func_reset_sigpipe; echo "$handledmodules" | LC_ALL=C join -v 2 - "$tmp"/queued-modules`
+    inmodules=`echo "$handledmodules" | LC_ALL=C join -v 2 - "$tmp"/queued-modules`
   done
   modules=`for m in $outmodules; do echo $m; done | LC_ALL=C sort -u`
   rm -f "$tmp"/queued-modules
@@ -3354,8 +3349,7 @@
   fi
   # Determine tests-related module list.
   echo "$final_modules" | LC_ALL=C sort -u > "$tmp"/final-modules
-  testsrelated_modules=`func_reset_sigpipe
-                        for module in $main_modules; do
+  testsrelated_modules=`for module in $main_modules; do
                           if test \`func_get_applicability $module\` = main; then
                             echo $module
                           fi
@@ -4256,8 +4250,7 @@
         if test -f "$destdir/$dir$ignore"; then
           if test -n "$dir_added" || test -n "$dir_removed"; then
             sed -e "s|^$anchor||" < "$destdir/$dir$ignore" | LC_ALL=C sort > "$tmp"/ignore
-            (func_reset_sigpipe
-             echo "$dir_added" | sed -e '/^$/d' | LC_ALL=C sort -u \
+            (echo "$dir_added" | sed -e '/^$/d' | LC_ALL=C sort -u \
                | LC_ALL=C join -v 1 - "$tmp"/ignore > "$tmp"/ignore-added
              echo "$dir_removed" | sed -e '/^$/d' | LC_ALL=C sort -u \
                | LC_ALL=C join -v 1 - "$tmp"/ignore > "$tmp"/ignore-removed