diff mbox series

[RFC] ubivol: add a property atomic-replaces

Message ID 1560261619-6695-2-git-send-email-philippe.reynes@softathome.com
State Changes Requested
Headers show
Series [RFC] ubivol: add a property atomic-replaces | expand

Commit Message

Philippe REYNES June 11, 2019, 2 p.m. UTC
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
---
 corelib/Makefile        |   1 +
 corelib/installer.c     |   9 +++
 corelib/ubi_interface.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/ubi_util.h      |  15 ++++
 4 files changed, 233 insertions(+)
 create mode 100644 corelib/ubi_interface.c
 create mode 100644 include/ubi_util.h
diff mbox series

Patch

diff --git a/corelib/Makefile b/corelib/Makefile
index d6edf65..414e508 100644
--- a/corelib/Makefile
+++ b/corelib/Makefile
@@ -20,4 +20,5 @@  lib-$(CONFIG_JSON)		+= parsing_library_libjson.o
 lib-$(CONFIG_CHANNEL_CURL)	+= channel_curl.o
 lib-$(CONFIG_SIGALG_RAWRSA)	+= swupdate_rsa_verify.o
 lib-$(CONFIG_SIGALG_CMS)	+= swupdate_cms_verify.o
+lib-$(CONFIG_UBIVOL)		+= ubi_interface.o
 
diff --git a/corelib/installer.c b/corelib/installer.c
index 2dda40a..8b626a3 100644
--- a/corelib/installer.c
+++ b/corelib/installer.c
@@ -32,6 +32,7 @@ 
 #include "parsers.h"
 #include "bootloader.h"
 #include "progress.h"
+#include "ubi_util.h"
 
 /*
  * function returns:
@@ -353,6 +354,14 @@  int install_images(struct swupdate_cfg *sw, int fdsw, int fromfile)
 		return ret;
 	}
 
+#ifdef CONFIG_UBIVOL
+	ret = run_ubi_swap(sw);
+	if (ret) {
+		ERROR("execute ubi swap failed");
+		return ret;
+	}
+#endif
+
 	ret = run_prepost_scripts(&sw->scripts, POSTINSTALL);
 	if (ret) {
 		ERROR("execute postinstall scripts failed");
diff --git a/corelib/ubi_interface.c b/corelib/ubi_interface.c
new file mode 100644
index 0000000..467cb79
--- /dev/null
+++ b/corelib/ubi_interface.c
@@ -0,0 +1,208 @@ 
+/*
+ * (C) Copyright 2019
+ * Philippe Reynes <philippe.reynes@softathome.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0-or-later
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <mtd/mtd-user.h>
+
+#include "flash.h"
+#include "util.h"
+#include "ubi_util.h"
+
+struct ubirnvol {
+	int dev_num;
+	char masternode[SWUPDATE_GENERAL_STRING_SIZE];
+	struct ubi_rnvol_req rnvol;
+	LIST_ENTRY(ubirnvol) next;
+};
+
+LIST_HEAD(ubirnvollist, ubirnvol);
+
+static void init_ubirnvollist(struct ubirnvollist *list)
+{
+	LIST_INIT(list);
+}
+
+static void free_ubirnvollist(struct ubirnvollist *list)
+{
+	struct ubirnvol *ubirnvol, *ubirnvol_tmp;
+
+	LIST_FOREACH_SAFE(ubirnvol, list, next, ubirnvol_tmp) {
+		LIST_REMOVE(ubirnvol, next);
+		free(ubirnvol);
+	}
+}
+
+static struct ubirnvol *search_ubirnvol(struct ubirnvollist *list, int dev_num)
+{
+	struct ubirnvol *rnvol;
+    
+	LIST_FOREACH(rnvol, list, next) {
+		if (rnvol->dev_num == dev_num)
+			return rnvol;
+	}
+
+	return NULL;
+}
+
+static int fill_ubirnvol(struct ubirnvol *ubirnvol,
+			 struct ubi_part *old_ubi_part,
+			 struct ubi_part *new_ubi_part)
+{
+	int old_dev_num, old_vol_id;
+	int new_dev_num, new_vol_id;
+	char *old_name, *new_name;
+	struct ubi_rnvol_req *rnvol;
+	int num_swap;
+
+	if (!ubirnvol || !old_ubi_part || !new_ubi_part)
+		return -1;
+
+	old_dev_num = old_ubi_part->vol_info.dev_num;
+	old_vol_id  = old_ubi_part->vol_info.vol_id;
+	old_name    = &old_ubi_part->vol_info.name[0];
+
+	new_dev_num = new_ubi_part->vol_info.dev_num;
+	new_vol_id  = new_ubi_part->vol_info.vol_id;
+	new_name    = &new_ubi_part->vol_info.name[0];
+
+	rnvol = &ubirnvol->rnvol;
+	num_swap = rnvol->count;
+
+	if ((ubirnvol->dev_num != old_dev_num) || (old_dev_num != new_dev_num))
+		return -1;
+
+	rnvol->ents[num_swap + 0].vol_id = old_vol_id;
+	rnvol->ents[num_swap + 0].name_len = strlen(new_name);
+	strcpy(&rnvol->ents[num_swap + 0].name[0], new_name);
+
+	rnvol->ents[num_swap + 1].vol_id = new_vol_id;
+	rnvol->ents[num_swap + 1].name_len = strlen(old_name);
+	strcpy(&rnvol->ents[num_swap + 1].name[0], old_name);
+
+	rnvol->count += 2;
+
+	return 0;
+}
+
+static struct ubirnvol *create_ubirnvol(struct ubi_part *old_ubi_part,
+					struct ubi_part *new_ubi_part)
+{
+	struct ubirnvol *ubirnvol;
+	int ret;
+
+	ubirnvol = (struct ubirnvol *)calloc(1, sizeof(*ubirnvol));
+	if (!ubirnvol)
+		goto out;
+
+	ubirnvol->dev_num = old_ubi_part->vol_info.dev_num;
+	snprintf(&ubirnvol->masternode[0], sizeof(ubirnvol->masternode),
+		 "/dev/ubi%d", old_ubi_part->vol_info.dev_num);
+
+	ret = fill_ubirnvol(ubirnvol, old_ubi_part, new_ubi_part);
+	if (ret) {
+		free(ubirnvol);
+		ubirnvol = NULL;
+	}
+
+ out:
+	return ubirnvol;
+}
+
+static int run_ubirnvol(struct ubirnvollist *list)
+{
+	struct flash_description *flash = get_flash_info();
+	libubi_t libubi = flash->libubi;    
+	struct ubirnvol *ubirnvol;
+	int ret = 0;
+
+	LIST_FOREACH(ubirnvol, list, next) {
+		ret = ubi_rnvols(libubi, ubirnvol->masternode, &ubirnvol->rnvol);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
+static struct ubi_part *search_volume(const char *str, struct ubilist *list)
+{
+	struct ubi_part *vol;
+
+	LIST_FOREACH(vol, list, next) {
+		if (strcmp(vol->vol_info.name, str) == 0)
+			return vol;
+	}
+	return NULL;
+}
+
+static struct ubi_part *search_volume_global(const char *str)
+{
+	struct flash_description *flash = get_flash_info();
+	struct mtd_info *mtd_info = &flash->mtd;
+	struct mtd_ubi_info *mtd_ubi_info;
+	struct ubi_part *ubivol;
+	int i;
+
+	for (i = mtd_info->lowest_mtd_num; i <= mtd_info->highest_mtd_num; i++) {
+		mtd_ubi_info = &flash->mtd_info[i];
+		ubivol = search_volume(str, &mtd_ubi_info->ubi_partitions);
+		if (ubivol)
+			return ubivol;
+	}
+	return NULL;
+}
+
+int run_ubi_swap(struct swupdate_cfg *sw)
+{
+	struct ubirnvollist ubirnvollist;
+	struct img_type *img;
+	struct ubi_part *old_ubi_part, *new_ubi_part;	
+	int ret, dev_num = -1;
+	
+	init_ubirnvollist(&ubirnvollist);
+	
+	LIST_FOREACH(img, &sw->images, next) {
+		char *tmpvol_name;
+		struct ubirnvol *ubirnvol;
+
+		tmpvol_name = dict_get_value(&img->properties, "atomic-replaces");
+		if (tmpvol_name) {
+			TRACE("atomic-replaces: will swap UBI volume %s <-> %s", img->volname, tmpvol_name);
+
+			old_ubi_part = search_volume_global(img->volname);
+			new_ubi_part = search_volume_global(tmpvol_name);
+
+			dev_num = old_ubi_part->vol_info.dev_num;
+
+			ubirnvol = search_ubirnvol(&ubirnvollist, dev_num);
+			if (ubirnvol) {
+				ret = fill_ubirnvol(ubirnvol, old_ubi_part, new_ubi_part);
+				if (ret)
+					goto out;
+			} else {
+				ubirnvol = create_ubirnvol(old_ubi_part, new_ubi_part);
+				if (!ubirnvol) {
+					ret = -ENOMEM;
+					goto out;
+				}
+				LIST_INSERT_HEAD(&ubirnvollist, ubirnvol, next);
+			}
+		}
+	}
+
+	ret = run_ubirnvol(&ubirnvollist);
+
+ out:
+	free_ubirnvollist(&ubirnvollist);
+
+	return ret;
+}
diff --git a/include/ubi_util.h b/include/ubi_util.h
new file mode 100644
index 0000000..3527ad1
--- /dev/null
+++ b/include/ubi_util.h
@@ -0,0 +1,15 @@ 
+/*
+ * (C) Copyright 2019
+ * Philippe Reynes <philippe.reynes@softathome.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0-or-later
+ */
+
+#ifndef _UBI_UTIL_H
+#define _UBI_UTIL_H
+
+#include "swupdate.h"
+
+int run_ubi_swap(struct swupdate_cfg *sw);
+
+#endif