diff mbox series

[2/2] versions: Split software config artifacts sw versions from runtime

Message ID 20251014163659.10267-2-clement@clementramirez.fr
State New
Delegated to: Stefano Babic
Headers show
Series [1/2] bsdqueue.h: Update bsdqueue.h header file | expand

Commit Message

Clement Ramirez Oct. 14, 2025, 4:36 p.m. UTC
From: Clement Ramirez <clement.ramirez@actia.fr>

The former implementation was updating a common list of installed
software versions each time an artifact was successfully
installed/executed.

This patch separate the software versions currently considered
installed and active (config files) from those brought by the
current update (runtime ones).

Signed-off-by: Clement Ramirez <clement.ramirez@actia.fr>
---
 core/artifacts_versions.c | 44 +++++++++++++++++++++++++++++++++++----
 core/installer.c          | 35 +++++++++++++++++++++++++++----
 core/stream_interface.c   |  7 +++++++
 corelib/lua_interface.c   |  6 +++---
 include/swupdate.h        |  1 +
 include/swupdate_image.h  |  3 ++-
 include/versions.h        |  2 ++
 parser/parse_external.c   |  4 ++--
 parser/parser.c           | 28 ++++++++++++-------------
 9 files changed, 102 insertions(+), 28 deletions(-)
diff mbox series

Patch

diff --git a/core/artifacts_versions.c b/core/artifacts_versions.c
index 18422b70..73d1799e 100644
--- a/core/artifacts_versions.c
+++ b/core/artifacts_versions.c
@@ -64,12 +64,13 @@  static int read_sw_version_file(struct swupdate_cfg *sw)
 				return -ENOMEM;
 			}
 			strlcpy(swcomp->name, name, sizeof(swcomp->name));
-			strlcpy(swcomp->version, version, sizeof(swcomp->version));
+			strlcpy(swcomp->config_version, version, sizeof(swcomp->config_version));
+			swcomp->runtime_version[0] = '\0';
 
 			LIST_INSERT_HEAD(&sw->installed_sw_list, swcomp, next);
 			TRACE("Installed %s: Version %s",
 					swcomp->name,
-					swcomp->version);
+					swcomp->config_version);
 			free(name);
 			free(version);
 		} else {
@@ -115,12 +116,13 @@  static int versions_settings(void *setting, void *data)
 		}
 
 		GET_FIELD_STRING(LIBCFG_PARSER, elem, "name", swcomp->name);
-		GET_FIELD_STRING(LIBCFG_PARSER, elem, "version", swcomp->version);
+		GET_FIELD_STRING(LIBCFG_PARSER, elem, "version", swcomp->config_version);
+		swcomp->runtime_version[0] = '\0';
 
 		LIST_INSERT_HEAD(&sw->installed_sw_list, swcomp, next);
 		TRACE("Installed %s: Version %s",
 			swcomp->name,
-			swcomp->version);
+			swcomp->config_version);
 	}
 
 	return 0;
@@ -261,3 +263,37 @@  int compare_versions(const char* left_version, const char* right_version)
 	DEBUG("Comparing lexicographically '%s' <-> '%s'", left_version, right_version);
 	return strcmp(left_version, right_version);
 }
+
+int backup_artifacts_versions(struct swver *dest, struct swver *src)
+{
+	struct sw_version *swcomp, *swcomp_copy;
+
+	LIST_INIT(dest);
+
+	LIST_FOREACH(swcomp, src, next) {
+		swcomp_copy = (struct sw_version *)calloc(1, sizeof(struct sw_version));
+		if (!swcomp_copy) {
+			ERROR("Could not create new version entry.");
+			free_image(swcomp_copy);
+			return -ENOMEM;
+		}
+
+		strlcpy(swcomp_copy->name, swcomp->name, sizeof(swcomp_copy->name));
+		strlcpy(swcomp_copy->runtime_version, swcomp->runtime_version,
+			sizeof(swcomp_copy->runtime_version));
+		strlcpy(swcomp_copy->config_version, swcomp->config_version,
+			sizeof(swcomp_copy->config_version));
+		LIST_INSERT_HEAD(dest, swcomp_copy, next);
+	}
+
+	return 0;
+}
+
+void restore_artifacts_versions(struct swver *dest, struct swver *src)
+{
+	struct swver tmp;
+
+	LIST_MOVE(src, &tmp, next);
+	LIST_MOVE(dest, src, next);
+	LIST_MOVE(&tmp, dest, next);
+}
\ No newline at end of file
diff --git a/core/installer.c b/core/installer.c
index 8cba1790..1b879373 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -205,13 +205,23 @@  static int generate_swversions(struct swupdate_cfg *cfg)
 	FILE *fp;
 	struct sw_version *swver;
 	struct swver *sw_ver_list = &cfg->installed_sw_list;
+	char *selected_version[SWUPDATE_GENERAL_STRING_SIZE];
 
 	fp = fopen(cfg->output_swversions, "w");
 	if (!fp)
 		return -EACCES;
 
 	LIST_FOREACH(swver, sw_ver_list, next) {
-		fprintf(fp, "%s\t\t%s\n", swver->name, swver->version);
+		if (!strlen(swver->runtime_version))
+		{
+			strncpy(selected_version, swver->config_version, sizeof(selected_version));
+		}
+		else
+		{
+			strncpy(selected_version, swver->runtime_version, sizeof(selected_version));
+		}
+
+		fprintf(fp, "%s\t\t%s\n", swver->name, selected_version);
 	}
 	fclose(fp);
 
@@ -324,12 +334,12 @@  static int update_installed_image_version(struct swver *sw_ver_list,
 		 * If component is already installed, update the version
 		 */
 		if (!strncmp(img->id.name, swver->name, sizeof(img->id.name))) {
-			strncpy(swver->version, img->id.version, sizeof(img->id.version));
+			strncpy(swver->runtime_version, img->id.runtime_version, sizeof(swver->runtime_version));
 			return true;
 		}
 	}
 
-	if (!strlen(img->id.version))
+	if (!strlen(img->id.runtime_version))
 		return false;
 
 	/*
@@ -342,7 +352,7 @@  static int update_installed_image_version(struct swver *sw_ver_list,
 	}
 
 	strlcpy(swcomp->name, img->id.name, sizeof(swcomp->name));
-	strlcpy(swcomp->version, img->id.version, sizeof(swcomp->version));
+	strlcpy(swcomp->runtime_version, img->id.runtime_version, sizeof(swcomp->runtime_version));
 	LIST_INSERT_HEAD(sw_ver_list, swcomp, next);
 
 	return true;
@@ -364,6 +374,13 @@  int install_images(struct swupdate_cfg *sw)
 	bool dry_run = sw->parms.dry_run;
 	bool dropimg;
 
+	/* In case of failure, we must restore the previous versions */
+	ret = backup_artifacts_versions(&sw->installed_sw_list_backup, &sw->installed_sw_list);
+	if (ret) {
+		ERROR("Could not backup current installed software versions");
+		return ret;
+	}
+
 	/* Extract all scripts, preinstall scripts must be run now */
 	const char* tmpdir_scripts = get_tmpdirscripts();
 	ret = extract_scripts(&sw->scripts);
@@ -526,6 +543,8 @@  void cleanup_files(struct swupdate_cfg *software) {
 	struct img_type *img_tmp;
 	struct hw_type *hw;
 	struct hw_type *hw_tmp;
+	struct sw_version *swver;
+	struct sw_version *swver_tmp;
 	const char* TMPDIR = get_tmpdir();
 	struct imglist *list[] = {&software->scripts};
 
@@ -557,6 +576,14 @@  void cleanup_files(struct swupdate_cfg *software) {
 	dict_drop_db(&software->bootloader);
 	dict_drop_db(&software->vars);
 
+	/*
+	 * Cleanup backup of installed software versions
+	 */
+	LIST_FOREACH_SAFE(swver, &software->installed_sw_list_backup, next, swver_tmp) {
+		LIST_REMOVE(swver, next);
+		free(swver);
+	}
+
 	/*
 	 * Drop Lua State if instantiated
 	 */
diff --git a/core/stream_interface.c b/core/stream_interface.c
index 8fadde3d..267bc2e6 100644
--- a/core/stream_interface.c
+++ b/core/stream_interface.c
@@ -760,6 +760,13 @@  void *network_initializer(void *data)
 						WARN("execute POST FAILURE scripts return error, ignoring..");
 					}
 				}
+
+				/*
+				* Restore the previous software versions list
+				* if the installation failed
+				*/
+				restore_artifacts_versions(&software->installed_sw_list,
+						       &software->installed_sw_list_backup);
 			} else {
 				/*
 				 * Clear the recovery variable to indicate to bootloader
diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index 6543dff7..2bf5fc11 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -297,8 +297,8 @@  static void lua_string_to_img(struct img_type *img, const char *key,
 			sizeof(img->id.name));
 	}
 	if (!strcmp(key, "version")) {
-		strncpy(img->id.version, value,
-			sizeof(img->id.version));
+		strncpy(img->id.runtime_version, value,
+			sizeof(img->id.runtime_version));
 	}
 	if (!strcmp(key, "filename")) {
 		strncpy(img->fname, value,
@@ -506,7 +506,7 @@  static void update_table(lua_State* L, struct img_type *img)
 		luaL_checktype(L, -1, LUA_TTABLE);
 
 		LUA_PUSH_IMG_STRING(img, "name", id.name);
-		LUA_PUSH_IMG_STRING(img, "version", id.version);
+		LUA_PUSH_IMG_STRING(img, "version", id.runtime_version);
 		LUA_PUSH_IMG_STRING(img, "filename", fname);
 		LUA_PUSH_IMG_STRING(img, "volume", volname);
 		LUA_PUSH_IMG_STRING(img, "type", type);
diff --git a/include/swupdate.h b/include/swupdate.h
index 59b085b6..356d30dc 100644
--- a/include/swupdate.h
+++ b/include/swupdate.h
@@ -98,6 +98,7 @@  struct swupdate_cfg {
 	struct hw_type hw;
 	struct hwlist hardware;
 	struct swver installed_sw_list;
+	struct swver installed_sw_list_backup;
 	struct swupdate_type_list swupdate_types;
 	struct imglist images;
 	struct imglist scripts;
diff --git a/include/swupdate_image.h b/include/swupdate_image.h
index 1bb37dc8..d204226a 100644
--- a/include/swupdate_image.h
+++ b/include/swupdate_image.h
@@ -32,7 +32,8 @@  typedef enum {
 
 struct sw_version {
 	char name[SWUPDATE_GENERAL_STRING_SIZE];
-	char version[SWUPDATE_GENERAL_STRING_SIZE];
+	char runtime_version[SWUPDATE_GENERAL_STRING_SIZE]; /*Version installed since swupdate is running*/
+	char config_version[SWUPDATE_GENERAL_STRING_SIZE]; /*Version referenced into versions config files*/
 	bool install_if_different;
 	bool install_if_higher;
 	LIST_ENTRY(sw_version) next;
diff --git a/include/versions.h b/include/versions.h
index 7f883be2..bf7f7f89 100644
--- a/include/versions.h
+++ b/include/versions.h
@@ -9,4 +9,6 @@ 
 
 #include "swupdate_settings.h"
 void get_sw_versions(swupdate_cfg_handle *handle, struct swupdate_cfg *sw);
+int backup_artifacts_versions(struct swver *dest, struct swver *src);
+void restore_artifacts_versions(struct swver *dest, struct swver *src);
 
diff --git a/parser/parse_external.c b/parser/parse_external.c
index d67bcca0..abdb835d 100644
--- a/parser/parse_external.c
+++ b/parser/parse_external.c
@@ -47,8 +47,8 @@  static void sw_append_stream(struct img_type *img, const char *key,
 			sizeof(img->id.name));
 	}
 	if (!strcmp(key, "version")) {
-		strlcpy(img->id.version, value,
-			sizeof(img->id.version));
+		strlcpy(img->id.runtime_version, value,
+			sizeof(img->id.runtime_version));
 	}
 	if (!strcmp(key, "mtdname") || !strcmp(key, "dest"))
 		strlcpy(img->mtdname, value,
diff --git a/parser/parser.c b/parser/parser.c
index 84bf036c..6c869a24 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -349,7 +349,7 @@  static int is_image_installed(struct swver *sw_ver_list,
     if (!sw_ver_list)
         return false;
 
-    if (!strlen(img->id.name) || !strlen(img->id.version) ||
+    if (!strlen(img->id.name) || !strlen(img->id.runtime_version) ||
         !img->id.install_if_different)
         return false;
 
@@ -358,10 +358,10 @@  static int is_image_installed(struct swver *sw_ver_list,
          * Check if name and version are identical
          */
         if (!strncmp(img->id.name, swver->name, sizeof(img->id.name)) &&
-            !compare_versions(img->id.version, swver->version)) {
+            !compare_versions(img->id.runtime_version, swver->config_version)) {
             TRACE("%s(%s) already installed, skipping...",
                   img->id.name,
-                  img->id.version);
+                  img->id.runtime_version);
 
             return true;
         }
@@ -378,13 +378,13 @@  static int is_image_higher(struct swver *sw_ver_list,
     if (!sw_ver_list)
         return false;
 
-    if (!strlen(img->id.name) || !strlen(img->id.version) ||
+    if (!strlen(img->id.name) || !strlen(img->id.runtime_version) ||
         !img->id.install_if_higher)
         return false;
 
     LIST_FOREACH(swver, sw_ver_list, next) {
-        const char* current_version = swver->version;
-        const char* proposed_version = img->id.version;
+        const char* current_version = swver->config_version;
+        const char* proposed_version = img->id.runtime_version;
 
         /*
          * Check if name are identical and the new version is lower
@@ -394,7 +394,7 @@  static int is_image_higher(struct swver *sw_ver_list,
             (compare_versions(proposed_version, current_version) <= 0)) {
             TRACE("%s(%s) has a higher or same version installed, skipping...",
                   img->id.name,
-                  img->id.version);
+                  img->id.runtime_version);
 
             return true;
         }
@@ -472,7 +472,7 @@  static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
 	seek_str[0] = '\0';
 
 	GET_FIELD_STRING(p, elem, "name", image->id.name);
-	GET_FIELD_STRING(p, elem, "version", image->id.version);
+	GET_FIELD_STRING(p, elem, "version", image->id.runtime_version);
 	GET_FIELD_STRING(p, elem, "filename", image->fname);
 	GET_FIELD_STRING(p, elem, "path", image->path);
 	GET_FIELD_STRING(p, elem, "volume", image->volname);
@@ -757,13 +757,13 @@  static int _parse_bootloader(parsertype p, void *cfg, void *setting, const char
 		 * to let allocate the place for the strings
 		 */
 		GET_FIELD_STRING(p, elem, "name", dummy.id.name);
-		GET_FIELD_STRING(p, elem, "value", dummy.id.version);
+		GET_FIELD_STRING(p, elem, "value", dummy.id.runtime_version);
 		skip = run_embscript(p, elem, &dummy, L, swcfg->embscript);
 		if (skip < 0) {
 			return -1;
 		}
 		if (!skip) {
-			dict_set_value(&swcfg->bootloader, dummy.id.name, dummy.id.version);
+			dict_set_value(&swcfg->bootloader, dummy.id.name, dummy.id.runtime_version);
 			TRACE("Bootloader var: %s = %s",
 				dummy.id.name,
 				dict_get_value(&swcfg->bootloader, dummy.id.name));
@@ -832,7 +832,7 @@  static int _parse_vars(parsertype p, void *cfg, void *setting, const char **node
 		 * to let allocate the place for the strings
 		 */
 		GET_FIELD_STRING(p, elem, "name", dummy.id.name);
-		GET_FIELD_STRING(p, elem, "value", dummy.id.version);
+		GET_FIELD_STRING(p, elem, "value", dummy.id.runtime_version);
 		skip = run_embscript(p, elem, &dummy, L, swcfg->embscript);
 		if (skip < 0)
 			return -1;
@@ -842,7 +842,7 @@  static int _parse_vars(parsertype p, void *cfg, void *setting, const char **node
 		/*
 		 * Store the variable in dictionary
 		 */
-		dict_set_value(&swcfg->vars, dummy.id.name, dummy.id.version);
+		dict_set_value(&swcfg->vars, dummy.id.name, dummy.id.runtime_version);
 
 		TRACE("SWUpdate var: %s = %s",
 		       dummy.id.name,
@@ -929,7 +929,7 @@  static int _parse_images(parsertype p, void *cfg, void *setting, const char **no
 			skip ? "Skip" : "Found",
 			image->compressed ? "compressed " : "",
 			strlen(image->id.name) ? " " : "", image->id.name,
-			strlen(image->id.version) ? " " : "", image->id.version,
+			strlen(image->id.runtime_version) ? " " : "", image->id.runtime_version,
 			image->fname,
 			strlen(image->volname) ? "volume" : "device",
 			strlen(image->volname) ? image->volname :
@@ -1025,7 +1025,7 @@  static int _parse_files(parsertype p, void *cfg, void *setting, const char **nod
 			skip ? "Skip" : "Found",
 			file->compressed ? "compressed " : "",
 			strlen(file->id.name) ? " " : "", file->id.name,
-			strlen(file->id.version) ? " " : "", file->id.version,
+			strlen(file->id.runtime_version) ? " " : "", file->id.runtime_version,
 			file->fname,
 			file->path,
 			strlen(file->device) ? file->device : "ROOTFS",