From cd1a612d1954182212e4bf03eadf924c2fb2332f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
Date: Mon, 11 Mar 2024 19:00:51 +0100
Subject: [PATCH] image-rauc: allow to specify an offset to skip input bytes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is useful for barebox images on (at least) i.MX8 to be written to
eMMC. There the first 32K of the image must be skipped.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 genimage.h       |  1 +
 image-rauc.c     | 36 ++++++++++++++++++++++++++++++++----
 test/rauc.config |  5 ++++-
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/genimage.h b/genimage.h
index 8c86e77..63995ac 100644
--- a/genimage.h
+++ b/genimage.h
@@ -45,6 +45,7 @@ struct partition {
 	cfg_bool_t no_automount;
 	cfg_bool_t fill;
 	const char *image;
+	off_t imageoffset;
 	struct list_head list;
 	int autoresize;
 	int in_partition_table;
diff --git a/image-rauc.c b/image-rauc.c
index 0b8f23e..8f405e4 100644
--- a/image-rauc.c
+++ b/image-rauc.c
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include "genimage.h"
 
@@ -68,6 +69,7 @@ static int rauc_generate(struct image *image)
 		struct image *child = image_get(part->image);
 		const char *file = imageoutfile(child);
 		const char *target = part->name;
+		char *tmptarget;
 		char *path, *tmp;
 
 		if (part->partition_type == RAUC_CERT)
@@ -105,10 +107,34 @@ static int rauc_generate(struct image *image)
 				goto out;
 		}
 
-		image_info(image, "adding file '%s' as '%s' ...\n",
-				child->file, target);
-		ret = systemp(image, "cp --remove-destination '%s' '%s/%s'",
-				file, tmpdir, target);
+		xasprintf(&tmptarget, "%s/%s", tmpdir, target);
+
+		image_info(image, "adding file '%s' as '%s' (offset=%lld)...\n",
+				child->file, target, (long long)part->imageoffset);
+
+		if (part->imageoffset) {
+			unlink(tmptarget);
+
+			/*
+			 * Starting with coreutils 9.1 you can use a 'B' suffix for
+			 * skip=N instead of iflag=skip_bytes to have N count bytes, not
+			 * (input) blocks.
+			 *
+			 * Note that dd doesn't behave as optimal as cp in the
+			 * else branch below because it doesn't preserve holes.
+			 * To improve here insert_image() should be extended to
+			 * support part->imageoffset != 0 and then it can
+			 * replace both commands.
+			 */
+			ret = systemp(image, "dd if='%s' of='%s' iflag=skip_bytes skip=%lld",
+					file, tmptarget, (long long)part->imageoffset);
+
+		} else {
+			ret = systemp(image, "cp --remove-destination '%s' '%s'",
+				      file, tmptarget);
+		}
+
+		free(tmptarget);
 		if (ret)
 			goto out;
 	}
@@ -193,6 +219,7 @@ static int rauc_parse(struct image *image, cfg_t *cfg)
 		part = xzalloc(sizeof *part);
 		part->name = cfg_title(filesec);
 		part->image = cfg_getstr(filesec, "image");
+		part->imageoffset = cfg_getint_suffix(filesec, "offset");
 		part->partition_type = RAUC_CONTENT;
 		list_add_tail(&part->list, &image->partitions);
 	}
@@ -219,6 +246,7 @@ static int rauc_setup(struct image *image, cfg_t *cfg)
 
 static cfg_opt_t file_opts[] = {
 	CFG_STR("image", NULL, CFGF_NONE),
+	CFG_STR("offset", "0", CFGF_NONE),
 	CFG_END()
 };
 
diff --git a/test/rauc.config b/test/rauc.config
index 9cb5801..f680f71 100644
--- a/test/rauc.config
+++ b/test/rauc.config
@@ -18,7 +18,10 @@ image test.raucb {
 }
 image test2.raucb {
 	rauc {
-		file data { image = "rauc2.content" }
+		file data {
+			image = "rauc2.content"
+			offset = 1
+		 }
 		manifest = "
 			[update]
 			compatible=genimage-test