On Tue, May 6, 2008 at 2:07 PM, David Rees <[EMAIL PROTECTED]> wrote:
>  Ah, missed that. I did see a few other places where it appears that
>  config.xml is written besides through the write_config routine...
>  Modifying write_config to update the config file atomically will be
>  straight forward and should cover most of the cases where the file is
>  commonly written.

OK, attached is a patch to /etc/config.inc that makes sure that the
config.xml and config.cache is updated atomically. The patch adds a
function function "write_safe_file" with 3 arguments: $file, $content,
$force_binary.

Tested on my local pfSense 1.2 box here, seems to work OK.

Let me know what you think!

If the patches I submitted look OK, do you think they'll make it into 1.2.1?

-Dave
--- config.inc.orig	2008-02-14 10:41:55.000000000 -0800
+++ config.inc	2008-05-06 14:23:24.000000000 -0700
@@ -1061,11 +1061,9 @@
 	conf_mount_rw();
 
 	/* write new configuration */
-	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
-	if (!$fd)
+	if (!write_safe_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
 		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
-	fwrite($fd, $xmlconfig);
-	fclose($fd);
+	}
 
 	if($g['platform'] == "embedded") {
 		cleanup_backupcache(5);
@@ -1082,11 +1080,7 @@
 	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
 
 	/* write config cache */
-	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
-	if ($fd) {
-		fwrite($fd, serialize($config));
-		fclose($fd);
-	}
+	write_safe_file("{$g['tmp_path']}/config.cache", serialize($config), true);
 
 	/* tell kernel to sync fs data */
 	mwexec("/bin/sync");
@@ -1096,6 +1090,45 @@
 	return $config;
 }
 
+/****f* config/write_safe_file
+ * NAME
+ *   write_safe_file - Write a file out atomically
+ * DESCRIPTION
+ *   write_safe_file() Writes a file out atomically by first writing to a
+ *   temporary file of the same name but ending with the pid of the current
+ *   process, them renaming the temporary file over the original.
+ * INPUTS
+ *   $filename	- string containing the filename of the file to write
+ *   $content	- string containing the file content to write to file
+ *   $force_binary	- boolean denoting whether we should force binary
+ *   mode writing.
+ * RESULT
+ *   boolean - true if successful, false if not
+ ******/
+function write_safe_file($file, $content, $force_binary) {
+	$tmp_file = $file . "." . getmypid();
+	$write_mode = $force_binary ? "wb" : "w";
+
+	$fd = fopen($tmp_file, $write_mode);
+	if (!$fd) {
+		// Unable to open temporary file for writing
+		return false;
+	}
+	if (!fwrite($fd, $content)) {
+		// Unable to write to temporary file
+		fclose($fd);
+		return false;
+	}
+	fclose($fd);
+
+	if (!rename($tmp_file, $file)) {
+		// Unable to move temporary file to original
+		unlink($tmp_file);
+		return false;
+	}
+	return true;
+}
+
 /****f* config/reset_factory_defaults
  * NAME
  *   reset_factory_defaults - Reset the system to its default configuration.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to