From 04934ab329767b4a1fde60438f769f9eb055fd9d Mon Sep 17 00:00:00 2001
From: Luca Boccassi <luca.boccassi@microsoft.com>
Date: Mon, 6 Sep 2021 13:19:47 +0100
Subject: [PATCH] portabled: refactor extraction/validation into a common
 helper

(cherry picked from commit 9ff61565be1efe5cc962964cde1af2278e554e9e)

Conflict:NA
Reference:https://github.com/systemd/systemd/commit/04934ab329767b4a1fde60438f769f9eb055fd9d
---
 src/portable/portable.c | 169 ++++++++++++++++++++++------------------
 1 file changed, 92 insertions(+), 77 deletions(-)

diff --git a/src/portable/portable.c b/src/portable/portable.c
index 765aedf852..02f4a692b0 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -528,14 +528,18 @@ static int portable_extract_by_path(
         return 0;
 }
 
-int portable_extract(
+static int extract_image_and_extensions(
                 const char *name_or_path,
                 char **matches,
                 char **extension_image_paths,
+                bool validate_sysext,
+                Image **ret_image,
+                OrderedHashmap **ret_extension_images,
                 PortableMetadata **ret_os_release,
                 Hashmap **ret_unit_files,
                 sd_bus_error *error) {
 
+        _cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
         _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
@@ -544,6 +548,9 @@ int portable_extract(
         int r;
 
         assert(name_or_path);
+        assert(matches);
+        assert(ret_image);
+        assert(ret_extension_images);
 
         r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
         if (r < 0)
@@ -574,17 +581,91 @@ int portable_extract(
         if (r < 0)
                 return r;
 
+        /* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
+         * match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
+        if (validate_sysext) {
+                _cleanup_fclose_ FILE *f = NULL;
+
+                r = take_fdopen_unlocked(&os_release->fd, "r", &f);
+                if (r < 0)
+                        return r;
+
+                r = parse_env_file(f, os_release->name,
+                                   "ID", &id,
+                                   "VERSION_ID", &version_id,
+                                   "SYSEXT_LEVEL", &sysext_level);
+                if (r < 0)
+                        return r;
+        }
+
         ORDERED_HASHMAP_FOREACH(ext, extension_images) {
+                _cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
                 _cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
+                _cleanup_strv_free_ char **extension_release = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
 
-                r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, NULL, &extra_unit_files, error);
+                r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
                 if (r < 0)
                         return r;
+
                 r = hashmap_move(unit_files, extra_unit_files);
                 if (r < 0)
                         return r;
+
+                if (!validate_sysext)
+                        continue;
+
+                r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
+                if (r < 0)
+                        return r;
+
+                r = load_env_file_pairs(f, extension_release_meta->name, &extension_release);
+                if (r < 0)
+                        return r;
+
+                r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
+                if (r == 0)
+                        return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
         }
 
+        *ret_image = TAKE_PTR(image);
+        *ret_extension_images = TAKE_PTR(extension_images);
+        if (ret_os_release)
+                *ret_os_release = TAKE_PTR(os_release);
+        if (ret_unit_files)
+                *ret_unit_files = TAKE_PTR(unit_files);
+
+        return 0;
+}
+
+int portable_extract(
+                const char *name_or_path,
+                char **matches,
+                char **extension_image_paths,
+                PortableMetadata **ret_os_release,
+                Hashmap **ret_unit_files,
+                sd_bus_error *error) {
+
+        _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
+        _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
+        _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
+        _cleanup_(image_unrefp) Image *image = NULL;
+        int r;
+
+        r = extract_image_and_extensions(name_or_path,
+                                         matches,
+                                         extension_image_paths,
+                                         /* validate_sysext= */ false,
+                                         &image,
+                                         &extension_images,
+                                         &os_release,
+                                         &unit_files,
+                                         error);
+        if (r < 0)
+                return r;
+
         if (hashmap_isempty(unit_files)) {
                 _cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
                 if (!extensions)
@@ -1166,91 +1247,25 @@ int portable_attach(
                 size_t *n_changes,
                 sd_bus_error *error) {
 
-        _cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
-        _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
         _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(lookup_paths_free) LookupPaths paths = {};
         _cleanup_(image_unrefp) Image *image = NULL;
         PortableMetadata *item;
-        Image *ext;
-        char **p;
         int r;
 
-        assert(name_or_path);
-
-        r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
-        if (r < 0)
-                return r;
-        if (!strv_isempty(extension_image_paths)) {
-                extension_images = ordered_hashmap_new(&image_hash_ops);
-                if (!extension_images)
-                        return -ENOMEM;
-
-                STRV_FOREACH(p, extension_image_paths) {
-                        _cleanup_(image_unrefp) Image *new = NULL;
-
-                        r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
-                        if (r < 0)
-                                return r;
-
-                        r = ordered_hashmap_put(extension_images, new->name, new);
-                        if (r < 0)
-                                return r;
-                        TAKE_PTR(new);
-                }
-        }
-
-        r = portable_extract_by_path(image->path, /* path_is_extension= */ false, matches, &os_release, &unit_files, error);
+        r = extract_image_and_extensions(name_or_path,
+                                         matches,
+                                         extension_image_paths,
+                                         /* validate_sysext= */ true,
+                                         &image,
+                                         &extension_images,
+                                         /* os_release= */ NULL,
+                                         &unit_files,
+                                         error);
         if (r < 0)
                 return r;
 
-        /* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
-         * match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
-        if (os_release) {
-                _cleanup_fclose_ FILE *f = NULL;
-
-                r = take_fdopen_unlocked(&os_release->fd, "r", &f);
-                if (r < 0)
-                        return r;
-
-                r = parse_env_file(f, os_release->name,
-                                   "ID", &id,
-                                   "VERSION_ID", &version_id,
-                                   "SYSEXT_LEVEL", &sysext_level);
-                if (r < 0)
-                        return r;
-        }
-
-        ORDERED_HASHMAP_FOREACH(ext, extension_images) {
-                _cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
-                _cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
-                _cleanup_strv_free_ char **extension_release = NULL;
-                _cleanup_fclose_ FILE *f = NULL;
-
-                r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
-                if (r < 0)
-                        return r;
-
-                r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
-                if (r < 0)
-                        return r;
-
-                r = load_env_file_pairs(f, extension_release_meta->name, &extension_release);
-                if (r < 0)
-                        return r;
-
-                r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
-                if (r == 0)
-                        return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
-                if (r < 0)
-                        return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
-
-                r = hashmap_move(unit_files, extra_unit_files);
-                if (r < 0)
-                        return r;
-        }
-
         if (hashmap_isempty(unit_files)) {
                 _cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
                 if (!extensions)
-- 
2.33.0

