autoconf-patches
[Top][All Lists]
Advanced

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

replace autom4te output file atomically


From: Ben Pfaff
Subject: replace autom4te output file atomically
Date: Mon, 11 Aug 2008 22:14:09 -0700
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.2 (gnu/linux)

In 2003, Joey Hess reported the following bug against Debian's
autoconf package (see http://bugs.debian.org/221483):

    I noticed that if I ctrl-c autoconf, it can leave a partially
    written, executable configure script. I was lucky enough to
    get a configure script that exited with a shell parse error,
    but if I had been unlucky, it might have exited 0 without
    doing all the tests I expected it to do.  That would have
    sucked to ship to users.

    There are many ways to update a file in a way that is not
    prone to these problems, and I suggest that autoconf adopt
    one of them.

In response, I patched Debian's Autoconf to (in most
circumstances) atomically replace auto4mte's output file using
rename, instead of overwriting it in place.  But until now I did
not get around to passing it upstream.

Anyway, here it is.  Compared to the version currently in Debian,
there are some added comments and the style is fixed to match GNU
style, but it should otherwise be equivalent.

Please let me know what you think.

(My legal paperwork for Autoconf is in progress.)

commit d12f01e5cb4790f06fca16ea025972320f5ded31
Author: Ben Pfaff <address@hidden>
Date:   Mon Aug 11 22:12:35 2008 -0700

    * bin/autom4te.in (handle_output): Atomically replace the output
    file, in most circumstances, instead of overwriting it, to avoid
    leaving a partially written output file.
    
    Signed-off-by: Ben Pfaff <address@hidden>

diff --git a/ChangeLog b/ChangeLog
index 4c4cc3a..a481173 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-08-11  Ben Pfaff  <address@hidden>
+
+       * bin/autom4te.in (handle_output): Atomically replace the output
+       file, in most circumstances, instead of overwriting it, to avoid
+       leaving a partially written output file.
+
 2008-08-06  Eric Blake  <address@hidden>
 
        Fix autoheader 2.62 regression on AC_DEFINE([__EXTENSIONS__]).
diff --git a/bin/autom4te.in b/bin/autom4te.in
old mode 100644
new mode 100755
index 685df41..1ea86da
--- a/bin/autom4te.in
+++ b/bin/autom4te.in
@@ -44,6 +44,7 @@ use Autom4te::FileUtils;
 use Autom4te::General;
 use Autom4te::XFile;
 use File::Basename;
+use File::Copy;
 use strict;
 
 # Data directory.
@@ -485,7 +486,6 @@ sub handle_m4 ($@)
   # Everything went ok: preserve the outputs.
   foreach my $file (map { $_ . $req->id } ($tcache, $ocache))
     {
-      use File::Copy;
       move ("${file}t", "$file")
        or fatal "cannot rename ${file}t as $file: $!";
     }
@@ -550,21 +550,36 @@ sub handle_output ($$)
     foreach (sort keys %forbidden);
   verb "allowed   tokens: $allowed";
 
-  # Read the (cached) raw M4 output, produce the actual result.  We
-  # have to use the 2nd arg to have Autom4te::XFile honor the third, but then
-  # stdout is to be handled by hand :(.  Don't use fdopen as it means
-  # we will close STDOUT, which we already do in END.
+  # Create temporary file to receive output, so that the new output
+  # can atomically replace the old output, or overwrite the old output
+  # file if for some reason that will not work.
   my $out = new Autom4te::XFile;
-  if ($output eq '-')
+  my $atomic_replace;
+  if ($output eq '-' || (-e $output && ! -f $output))
     {
       $out->open (">$output");
+      $atomic_replace = 0;
     }
   else
     {
-      $out->open($output, O_CREAT | O_WRONLY | O_TRUNC, oct ($mode));
+      $out->open ("$output.tmp", O_CREAT | O_WRONLY | O_TRUNC, oct ($mode));
+      if ($out)
+       {
+         $atomic_replace = 1;
+       }
+      else
+       {
+         $out->open ($output, O_CREAT | O_WRONLY | O_TRUNC, oct ($mode));
+         $atomic_replace = 0;
+       }
     }
   fatal "cannot create $output: $!"
     unless $out;
+
+  # Read the (cached) raw M4 output, produce the actual result.  We
+  # have to use the 2nd arg to have Autom4te::XFile honor the third, but then
+  # stdout is to be handled by hand :(.  Don't use fdopen as it means
+  # we will close STDOUT, which we already do in END.
   my $in = new Autom4te::XFile ("< " . open_quote ($ocache . $req->id));
 
   my %prohibited;
@@ -600,6 +615,12 @@ sub handle_output ($$)
 
   $out->close();
 
+  if ($atomic_replace && !rename ("$output.tmp", "$output"))
+    {
+      move ("${output}.tmp", "$output")
+       or fatal "cannot rename ${output}.tmp as $output: $!";
+    }
+
   # If no forbidden words, we're done.
   return
     if ! %prohibited;



-- 
"MONO - Monochrome Emulation
 This field is used to store your favorite bit."
--FreeVGA Attribute Controller Reference




reply via email to

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