autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Diagnose write errors in config.status


From: Ralf Wildenhues
Subject: Re: Diagnose write errors in config.status
Date: Sat, 17 Nov 2007 13:34:42 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

Here we go with complete write failure checking in status.m4 for
everything not going to stderr or config.log.  For auditing purposes,
I inspected the configure and config.status scripts of test 116
(AC_CONFIG_FILES, HEADERS, LINKS and COMMANDS) manually, and for testing
purposes, I basically negated the output status of every writing command
(one at a time) to ensure that it provokes a test failure somewhere, and
that error output is sensible.  I added tests to the suite for code
paths which apparently weren't exercised before.

One notable issue I stumbled over is that instances of AC_MSG_* should
not appear in unquoted here-documents, because then $as_me is expanded
too early, and `\n' may expand to `n' wrongly.

I'll apply in a couple of days, unless there are issues with this patch.

Cheers,
Ralf

    Diagnose and guard against write errors dealing with config.status.

    The general idea is this: all write failures from `configure'
    writing `config.status' are indicated by $ac_write_error, which
    is only checked at the end.  This is safe because config.status
    code is not executed before the file is complete.  Other write
    failures, be they inside config.status, or in sub shell/awk
    scripts spawned from configure or config.status, typically need
    earlier checking, as their results are used right afterwards.
    * lib/autoconf/status.m4 (AC_OUTPUT): Initialize `ac_write_fail'
    before writing config.status, check afterwards.
    (_AC_OUTPUT_FILES_PREPARE, _AC_OUTPUT_FILE)
    (_AC_OUTPUT_HEADERS_PREPARE,_AC_OUTPUT_CONFIG_STATUS):
    Set `ac_write_error' for write failures to config.status.  Barf
    upon write failures to temporary files.
    Adjust note about closing and reopening the here-document.
    (_AC_OUTPUT_HEADER, _AC_OUTPUT_LINK, _AC_OUTPUT_COMMAND)
    (_AC_OUTPUT_MAIN_LOOP): Likewise, adjust note about closing and
    reopening the here-document.
    * tests/torture.at (AC_CONFIG_FILES, HEADERS, LINKS and COMMANDS):
    Ensure `ac_write_error' does not escape into config.status.
    Also, add a couple of code paths not yet exercised in the test
    suite: a config file with input from stdin, and a config header
    output to stdout.
    Suggestion for catching write errors by Bruno Haible.

diff --git a/lib/autoconf/status.m4 b/lib/autoconf/status.m4
index 4a617a6..3372a8b 100644
--- a/lib/autoconf/status.m4
+++ b/lib/autoconf/status.m4
@@ -335,7 +335,8 @@ m4_define([_AC_AWK_LITERAL_LIMIT],
 # This code was written by Dan Manthey and rewritten by Ralf Wildenhues.
 #
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 #
 m4_define([_AC_OUTPUT_FILES_PREPARE],
 [# Set up the scripts for CONFIG_FILES section.
@@ -359,12 +360,13 @@ m4_ifdef([_AC_SUBST_FILES],
   ac_cs_awk_pipe_fini=
 else
   ac_cs_awk_getline=false
-  ac_cs_awk_pipe_init="print \"cat <<'|#_!!_#|'\""
+  ac_cs_awk_pipe_init="print \"cat <<'|#_!!_#|' &&\""
   ac_cs_awk_read_file='
       print "|#_!!_#|"
-      print "cat " F[key]
+      print "cat " F[key] " &&"
       '$ac_cs_awk_pipe_init
-  ac_cs_awk_pipe_fini='END { print "|#_!!_#|" }'
+  # The final `:' finishes the AND list.
+  ac_cs_awk_pipe_fini='END { print "|#_!!_#|"; print ":" }'
 fi]])
 ac_cr='
'
 ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
@@ -385,31 +387,34 @@ fi])],
 [m4_define([_AC_SUBST_CMDS],
 [| $AWK -f "$tmp/subs.awk"])])dnl
 
-echo 'BEGIN {' >"$tmp/subs1.awk"
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
 _ACEOF
 
 m4_ifdef([_AC_SUBST_FILES],
 [# Create commands to substitute file output variables.
 {
-  echo "cat >>$CONFIG_STATUS <<_ACEOF"
-  echo 'cat >>"\$tmp/subs1.awk" <<\\_ACAWK'
-  echo "$ac_subst_files" | sed 's/.*/F@<:@"&"@:>@="$&"/'
-  echo "_ACAWK"
+  echo "cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1" &&
+  echo 'cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&' &&
+  echo "$ac_subst_files" | sed 's/.*/F@<:@"&"@:>@="$&"/' &&
+  echo "_ACAWK" &&
   echo "_ACEOF"
-} >conf$$files.sh
-. ./conf$$files.sh
+} >conf$$files.sh &&
+. ./conf$$files.sh ||
+  AC_MSG_ERROR([could not make $CONFIG_STATUS])
 rm -f conf$$files.sh
 ])dnl
 
 {
-  echo "cat >conf$$subs.awk <<_ACEOF"
-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/'
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
   echo "_ACEOF"
-} >conf$$subs.sh
+} >conf$$subs.sh ||
+  AC_MSG_ERROR([could not make $CONFIG_STATUS])
 ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
-  . ./conf$$subs.sh
+  . ./conf$$subs.sh ||
+    AC_MSG_ERROR([could not make $CONFIG_STATUS])
 
 dnl Do not use grep on conf$$subs.awk, since AIX grep has a line length limit.
   if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = 
$ac_delim_num; then
@@ -448,8 +453,8 @@ dnl   
http://www.gnu.org/software/gawk/manual/html_node/Gory-Details.html
 dnl - Writing `$ 0' prevents expansion by both the shell and m4 here.
 dnl
 dnl m4-double-quote most of the scripting for readability.
-[cat >>$CONFIG_STATUS <<_ACEOF
-cat >>"\$tmp/subs1.awk" <<\\_ACAWK
+[cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
 _ACEOF
 sed -n '
 h
@@ -493,11 +498,11 @@ t delim
   N
   s/\n//
 }
-' >>$CONFIG_STATUS
+' >>$CONFIG_STATUS || ac_write_fail=1
 rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 _ACAWK
-cat >>"\$tmp/subs1.awk" <<_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
   for (key in S) S_is_set[key] = 1
   FS = ""
 ]m4_ifdef([_AC_SUBST_FILES],
@@ -529,12 +534,15 @@ cat >>"\$tmp/subs1.awk" <<_ACAWK
   }]])[
   print line
 }
-]m4_ifdef([_AC_SUBST_FILES],
-[\$ac_cs_awk_pipe_fini])[
+]dnl end of double-quoted part
+m4_ifdef([_AC_SUBST_FILES],
+[\$ac_cs_awk_pipe_fini])
 _ACAWK
-sed "s/\$ac_cr\\\$//; s/\$ac_cr/\$ac_cs_awk_cr/g" < "\$tmp/subs1.awk" > 
"\$tmp/subs.awk"
 _ACEOF
-]dnl end of double-quoted part
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" < "$tmp/subs1.awk" > 
"$tmp/subs.awk" \
+  || AC_MSG_ERROR([could not setup config files machinery])
+_ACEOF
 
 # VPATH may cause trouble with some makes, so we remove $(srcdir),
 # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
@@ -551,7 +559,7 @@ s/^[^=]*=[   ]*$//
 }']
 fi
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 fi # test -n "$CONFIG_FILES"
 
 ])# _AC_OUTPUT_FILES_PREPARE
@@ -562,7 +570,8 @@ fi # test -n "$CONFIG_FILES"
 # Do the variable substitutions to create the Makefiles or whatever.
 #
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 #
 m4_define([_AC_OUTPUT_FILE],
 [
@@ -586,7 +595,7 @@ AC_PROVIDE_IFELSE([AC_PROG_MKDIR_P],
 _ACEOF
 
 m4_ifndef([AC_DATAROOTDIR_CHECKED],
-[cat >>$CONFIG_STATUS <<\_ACEOF
+[cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # If the template does not know about datarootdir, expand it.
 # FIXME: This hack should be removed a few years after 2.60.
 ac_datarootdir_hack=; ac_datarootdir_seen=
@@ -603,7 +612,7 @@ m4_foreach([_AC_Var], m4_defn([_AC_datarootdir_vars]),
 address@hidden(address@hidden|address@hidden, _AC_datarootdir_vars)@*)
   AC_MSG_WARN([$ac_file_inputs seems to ignore the --datarootdir setting])
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
   ac_datarootdir_hack='
   m4_foreach([_AC_Var], m4_defn([_AC_datarootdir_vars]),
               [s&@_AC_Var@&$_AC_Var&g
@@ -616,11 +625,11 @@ _ACEOF
 # Neutralize VPATH when `$srcdir' = `.'.
 # Shell code in configure.ac might set extrasub.
 # FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
   sed "$ac_vpsub
 $extrasub
 _ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 :t
 [/@[a-zA-Z_][a-zA-Z_0-9]*@/!b]
 dnl configure_input is a somewhat special, so we don't call AC_SUBST_TRACE.
@@ -690,14 +699,16 @@ AC_DEFUN([AC_CONFIG_HEADER],
 # Support multiline #defines.
 #
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 #
 m4_define([_AC_OUTPUT_HEADERS_PREPARE],
 [# Set up the scripts for CONFIG_HEADERS section.
 # No need to generate them if there are no CONFIG_HEADERS.
 # This happens for instance with `./config.status Makefile'.
 if test -n "$CONFIG_HEADERS"; then
-cat >"$tmp/defines.awk" <<\_ACAWK
+dnl This `||' list is finished at the end of _AC_OUTPUT_HEADERS_PREPARE.
+cat >"$tmp/defines.awk" <<\_ACAWK ||
 BEGIN {
 _ACEOF
 
@@ -781,9 +792,9 @@ s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
 b cont
 ' <confdefs.h | sed '
 s/'"$ac_delim"'/"\\\
-"/g' >>$CONFIG_STATUS
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
 
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
   for (key in D) D_is_set[key] = 1
   FS = ""
 }
@@ -818,8 +829,9 @@ cat >>$CONFIG_STATUS <<_ACEOF
 ]dnl End of double-quoted section
 _ACAWK
 _ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+dnl finish `||' list indicating write error:
+  AC_MSG_ERROR([could not setup config headers machinery])
 fi # test -n "$CONFIG_HEADERS"
 
 ])# _AC_OUTPUT_HEADERS_PREPARE
@@ -832,7 +844,8 @@ fi # test -n "$CONFIG_HEADERS"
 # `config.h.in'.
 #
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 #
 m4_define([_AC_OUTPUT_HEADER],
 [
@@ -917,7 +930,8 @@ update, you should probably tune the result yourself.])# 
AC_LINK_FILES
 # _AC_OUTPUT_LINK
 # ---------------
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 m4_define([_AC_OUTPUT_LINK],
 [
   #
@@ -993,7 +1007,8 @@ AC_CONFIG_COMMANDS([default-]_AC_OUTPUT_COMMANDS_CNT, 
[[$1]], [[$2]])dnl
 # _AC_OUTPUT_COMMAND
 # ------------------
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 m4_define([_AC_OUTPUT_COMMAND],
 [  AC_MSG_NOTICE([executing $ac_file commands])
 ])
@@ -1231,11 +1246,15 @@ dnl Commands to run before creating config.status.
 AC_OUTPUT_COMMANDS_PRE()dnl
 
 : ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
 ac_clean_files_save=$ac_clean_files
 ac_clean_files="$ac_clean_files $CONFIG_STATUS"
 _AC_OUTPUT_CONFIG_STATUS()dnl
 ac_clean_files=$ac_clean_files_save
 
+test $ac_write_fail = 0 ||
+  AC_MSG_ERROR([write failure creating $CONFIG_STATUS])
+
 dnl Commands to run after config.status was created
 AC_OUTPUT_COMMANDS_POST()dnl
 
@@ -1276,7 +1295,7 @@ m4_define([_AC_OUTPUT_CONFIG_STATUS],
 [AC_MSG_NOTICE([creating $CONFIG_STATUS])
 dnl AS_MESSAGE_LOG_FD is not available yet:
 m4_rename([AS_MESSAGE_LOG_FD], [_AC_save_AS_MESSAGE_LOG_FD])dnl
-cat >$CONFIG_STATUS <<_ACEOF
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 #! $SHELL
 # Generated by $as_me.
 # Run this file to recreate the current configuration.
@@ -1289,7 +1308,7 @@ ac_cs_silent=false
 SHELL=\${CONFIG_SHELL-$SHELL}
 _ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 AS_SHELL_SANITIZE
 dnl Watch out, this is directly the initializations, do not use
 dnl AS_PREPARE, otherwise you'd get it output in the initialization
@@ -1316,7 +1335,7 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q`
 
 _ACEOF
 
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 # Files that config.status was made for.
 m4_ifdef([_AC_SEEN_CONFIG(FILES)],
 [config_files="$ac_config_files"
@@ -1333,7 +1352,7 @@ m4_ifdef([_AC_SEEN_CONFIG(COMMANDS)],
 
 _ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 ac_cs_usage="\
 \`$as_me' instantiates files from templates according to the
 current configuration.
@@ -1377,7 +1396,7 @@ $config_commands
 Report bugs to <address@hidden>."
 
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
 m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.status[]dnl
 m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
@@ -1402,7 +1421,7 @@ AC_PROVIDE_IFELSE([AC_PROG_AWK],
 test -n "\$AWK" || AWK=awk
 _ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # The default lists apply if the user does not specify any file.
 ac_need_defaults=:
 while test $[#] != 0
@@ -1469,7 +1488,7 @@ if $ac_cs_silent; then
 fi
 
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 dnl Check this before opening the log, to avoid a bug on MinGW,
 dnl which prohibits the recursive instance from truncating an open log.
 if \$ac_cs_recheck; then
@@ -1482,7 +1501,7 @@ if \$ac_cs_recheck; then
 fi
 
 _ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 dnl Open the log:
 m4_rename([_AC_save_AS_MESSAGE_LOG_FD], [AS_MESSAGE_LOG_FD])dnl
 exec AS_MESSAGE_LOG_FD>>config.log
@@ -1493,7 +1512,7 @@ exec AS_MESSAGE_LOG_FD>>config.log
 } >&AS_MESSAGE_LOG_FD
 
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 m4_ifdef([_AC_OUTPUT_COMMANDS_INIT],
 [#
 # INIT-COMMANDS
@@ -1502,7 +1521,7 @@ _AC_OUTPUT_COMMANDS_INIT
 ])dnl
 _ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 
 # Handling of arguments.
 for ac_config_target in $ac_config_targets
@@ -1525,7 +1544,8 @@ chmod +x $CONFIG_STATUS
 # The main loop in $CONFIG_STATUS.
 #
 # This macro is expanded inside a here document.  If the here document is
-# closed, it has to be reopened with "cat >>$CONFIG_STATUS <<\_ACEOF".
+# closed, it has to be reopened with
+# "cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1".
 #
 AC_DEFUN([_AC_OUTPUT_MAIN_LOOP],
 [
diff --git a/tests/torture.at b/tests/torture.at
index a87a33b..80b1782 100644
--- a/tests/torture.at
+++ b/tests/torture.at
@@ -232,11 +232,23 @@ AT_CHECK_CONFIG_CREATION(link)
 
 # Create a file
 AT_CHECK_CONFIG_CREATION_NOWRITE(file)
+# Create a file with bits from stdin
+AT_CHECK([echo from-stdin | ./config.status --file=file:-],
+        [0], [ignore])
+AT_CHECK([grep from-stdin file], [], [from-stdin
+])
+# Force write error creating a file on stdout
 AT_CHECK([./config.status --file=-:input </dev/null >/dev/full],
         [1], [ignore], [ignore])
 
 # Create a header
 AT_CHECK_CONFIG_CREATION_NOWRITE(header)
+# Create a header on stdout
+AT_CHECK([./config.status --header=-:input </dev/null],
+        [0], [stdout], [ignore])
+AT_CHECK([grep OK stdout], [], [OK
+])
+# Force write error creating a header on stdout
 AT_CHECK([./config.status --header=-:input </dev/null >/dev/full],
         [1], [ignore], [ignore])
 
@@ -246,6 +258,9 @@ AT_CHECK_CONFIG_CREATION_NOWRITE(command)
 # Create a link
 AT_CHECK_CONFIG_CREATION_NOWRITE(link)
 
+# Check that no use of `ac_write_fail' escaped into config.status
+AT_CHECK([grep ac_write_fail config.status], [1])
+
 AT_CLEANUP
 
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]