From 5e52c720de765ed5563ec0364d168fef60a5807c Mon Sep 17 00:00:00 2001
From: Andrei Gherzan <andrei.gherzan@huawei.com>
Date: Mon, 13 Sep 2021 16:46:26 +0100
Subject: [PATCH] ohos-image.bbclass: Copy boot assets to root filesystem

This implements logic as a rootfs postprocess command where the set of
boot artifacts are provided as part of the root filesystem. The reason
is that the system update components assume only the root filesystem as
part of the update payload while boot files are also needed depending on
the BSP. For example, RaspberryPi update process would update the kernel
and dtbs on the boot partition too.

The boot files are copied to the path defined by
ROOTFS_BOOT_ARTIFACTS_PATH, relative to the root of the root filesystem.

SOme of the logic in this mechanism are based on the current
implementation of the bootimg-partition wic plugin.

Fixes https://git.ostc-eu.org/OSTC/OHOS/meta-ohos/-/issues/104

Signed-off-by: Andrei Gherzan <andrei.gherzan@huawei.com>
---
 meta-ohos-core/classes/ohos-image.bbclass | 90 +++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/meta-ohos-core/classes/ohos-image.bbclass b/meta-ohos-core/classes/ohos-image.bbclass
index 7d46446a..1e699801 100644
--- a/meta-ohos-core/classes/ohos-image.bbclass
+++ b/meta-ohos-core/classes/ohos-image.bbclass
@@ -82,3 +82,93 @@ IMAGE_FSTYPES_qemux86-64 ?= "wic wic.bz2"
 WKS_FILE_qemux86-64 ?= "x-qemux86-directdisk.wks.in"
 
 WKS_FILE_seco-imx8mm-c61 ?= "x-imx-uboot-bootpart.wks.in"
+
+#
+# Deploy boot partition artifacts to the root partition. This is part of the
+# system update design where the update payload is defined as the root
+# filesystem. In order to avoid multiple payloads, we include the boot assets
+# in the root filesystem.
+#
+
+# The path relative to the root of the root filesystem where to deploy the boot
+# artifacts.
+ROOTFS_BOOT_ARTIFACTS_PATH ?= "usr/lib/sysota/boot-assets"
+
+def run_cmd(cmd):
+    """
+    Run a cmd (string) and fail if exit code is non zero.
+    """
+
+    import subprocess
+    try:
+        subprocess.check_call(cmd.split())
+    except subprocess.CalledProcessError as e:
+        bb.fatal("Command \"%s\" failed with exit code %s." % (cmd , e.returncode))
+
+python deploy_boot_artifacts_to_rootfs() {
+    """
+    This functionality follows the general logic in bootimg-partition but is
+    adapted to work as a root filesystem post install function.
+    """
+
+    import re
+    from glob import glob
+
+    boot_files = d.getVar('IMAGE_BOOT_FILES')
+    if not boot_files:
+        # Nothing to do if IMAGE_BOOT_FILES is not defined. Custom wic plugins
+        # are not supported.
+        bb.warn('IMAGE_BOOT_FILES empty, so no boot files will be included in the rootfs')
+        return
+    deploy_dir = d.getVar('DEPLOY_DIR_IMAGE')
+    rootfs_dir = d.getVar('IMAGE_ROOTFS')
+    rootfs_boot_dir = d.getVar('ROOTFS_BOOT_ARTIFACTS_PATH')
+    if rootfs_boot_dir:
+        rootfs_dir = os.path.join(rootfs_dir, rootfs_boot_dir)
+
+    deploy_files = []
+    for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files):
+        if ';' in src_entry:
+            dst_entry = tuple(src_entry.split(';'))
+            if not dst_entry[0] or not dst_entry[1]:
+                bb.fatal('Malformed IMAGE_BOOT_FILES entry: %s' % src_entry)
+        else:
+            dst_entry = (src_entry, src_entry)
+        bb.debug(1, 'Destination entry: %r' % str(dst_entry))
+        deploy_files.append(dst_entry)
+
+    install_task = [];
+    for deploy_entry in deploy_files:
+        src, dst = deploy_entry
+        if '*' in src:
+            # by default install files under their basename
+            entry_name_fn = os.path.basename
+            if dst != src:
+                # unless a target name was given, then treat name
+                # as a directory and append a basename
+                entry_name_fn = lambda name: \
+                                os.path.join(dst,
+                                             os.path.basename(name))
+
+            srcs = glob(os.path.join(deploy_dir, src))
+
+            bb.debug(1, 'Globbed sources: %s' % ', '.join(srcs))
+            for entry in srcs:
+                src = os.path.relpath(entry, deploy_dir)
+                entry_dst_name = entry_name_fn(entry)
+                install_task.append((src, entry_dst_name))
+        else:
+            install_task.append((src, dst))
+
+    for task in install_task:
+        src_path, dst_path = task
+        bb.debug(1, 'Install %s as %s' % (src_path, dst_path))
+        if os.path.exists(os.path.join(rootfs_dir, dst_path)):
+            bb.fatal("%s already exists in the root filesystem. Fix to avoid overwriting files." % dst_path)
+        install_cmd = "install -m 0644 -D %s %s" \
+                      % (os.path.join(deploy_dir, src_path),
+                         os.path.join(rootfs_dir, dst_path))
+        run_cmd(install_cmd)
+}
+
+ROOTFS_POSTPROCESS_COMMAND += "deploy_boot_artifacts_to_rootfs;"
-- 
GitLab