diff mbox series

raw_handler: Add atomic-install support

Message ID 20220203185856.28649-1-colin.mcallister@garmin.com
State Changes Requested
Headers show
Series raw_handler: Add atomic-install support | expand

Commit Message

McAllister, Colin Feb. 3, 2022, 6:58 p.m. UTC
Add property for raw file handler that installs file to .tmp file.  Once
the .tmp file is installed, it is atomically renamed to the specified
file in path.  This ensures that a partial install does not affect the
currently installed file.

Signed-off-by: Colin McAllister <colin.mcallister@garmin.com>
---
 doc/source/sw-description.rst |  7 +++++++
 handlers/raw_handler.c        | 28 +++++++++++++++++++++++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/doc/source/sw-description.rst b/doc/source/sw-description.rst
index 3de3636..6901a72 100644
--- a/doc/source/sw-description.rst
+++ b/doc/source/sw-description.rst
@@ -738,6 +738,13 @@  As a general rule, swupdate doesn't copy out a file if the destination path
 doesn't exists. This behavior could be changed using the special property
 "create-destination".
 
+As another general rule, swupdate installs the file directly to the specified
+path.  If the destination file is intended to be atomically installed, the
+special property "atomic-install" may be set to "true".  This installs the
+file to the specified path with ".tmp" apppended to the filename.  In the case
+where a file already exists with the specified path, the atomic install prevents
+the original file from being overwritten until the temp file is installed.
+
 Scripts
 -------
 
diff --git a/handlers/raw_handler.c b/handlers/raw_handler.c
index 619a2f4..3fab630 100644
--- a/handlers/raw_handler.c
+++ b/handlers/raw_handler.c
@@ -206,6 +206,7 @@  static int install_raw_file(struct img_type *img,
 	void __attribute__ ((__unused__)) *data)
 {
 	char path[255];
+	char tmp_path[255];
 	int fdout;
 	int ret = 0;
 	int use_mount = (strlen(img->device) && strlen(img->filesystem)) ? 1 : 0;
@@ -237,6 +238,13 @@  static int install_raw_file(struct img_type *img,
 		}
 	}
 
+	if (strtobool(dict_get_value(&img->properties, "atomic-install"))) {
+		if (snprintf(tmp_path, sizeof(path), "%s%s", img->path, ".tmp") >= (int)sizeof(path)) {
+			ERROR("Temp path too long: %s%s", img->path, ".tmp");
+			return -1;
+		}
+	}
+
 	TRACE("Installing file %s on %s",
 		img->fname, path);
 
@@ -249,7 +257,12 @@  static int install_raw_file(struct img_type *img,
 		}
 	}
 
-	fdout = openfileoutput(path);
+	if (strtobool(dict_get_value(&img->properties, "atomic-install"))) {
+		fdout = openfileoutput(tmp_path);
+	}
+	else {
+		fdout = openfileoutput(path);
+	}
 	if (fdout < 0)
 		return fdout;
 	if (!img_check_free_space(img, fdout)) {
@@ -260,8 +273,21 @@  static int install_raw_file(struct img_type *img,
 	if (ret< 0) {
 		ERROR("Error copying extracted file");
 	}
+
+	if (strtobool(dict_get_value(&img->properties, "atomic-install"))) {
+		if(fsync(fdout)) {
+			ERROR("Error writing %s to disk: %s", tmp_path, strerror(errno));
+		}
+	}
+	
 	close(fdout);
 
+	if (strtobool(dict_get_value(&img->properties, "atomic-install"))) {
+		if(rename(tmp_path, path)) {
+			ERROR("Error renaming %s to %s: %s", tmp_path, path, strerror(errno));
+		}
+	}
+
 	if (use_mount) {
 		swupdate_umount(DATADST_DIR);
 	}