]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
portable: Add ExtensionImage drop-in for any extension
authorRodrigo Campos <rodrigo@amutable.com>
Fri, 27 Feb 2026 17:10:40 +0000 (18:10 +0100)
committerRodrigo Campos <rodrigo@amutable.com>
Tue, 3 Mar 2026 08:38:28 +0000 (09:38 +0100)
Before this patch, when running:

portablectl attach --extension ext.raw ./base.raw

No drop-in is added for the "ExtensionImages" if there aren't units from
the extension loaded.

But the extension can just overlay files, as in my case. So before this
patch, I also need to manually add a drop-in with "ExtensionImages=" for
it to really be loaded.

Let's just always add the drop-in for extensions. This way, it works for
extensions that just overlay files too.

Please note this commit just removes the if (simpler to view the diff
with git show -w). Also, the if checked for m->image_path being not
NULL, but removing it shouldn't cause a NULL pointer dereference.
Because m->image_path is not used inside the if (it was needed just for
the if itself) and image_path is asserted at the beginning of the
function to be non-NULL too.

This was like this since the beginning of time in 907952bbc9
("portabled: add --extension parameter for layered images support")

src/portable/portable.c

index 2f6db85ff9121694e39d2e48938edeea60e770cc..df505bbe2d5d3c4e8b2b36a9605ceaefdcae9e02 100644 (file)
@@ -1491,65 +1491,64 @@ static int install_chroot_dropin(
                 if (r < 0)
                         return r;
 
-                if (m->image_path && !path_equal(m->image_path, image_path))
-                        ORDERED_HASHMAP_FOREACH(ext, extension_images) {
+                ORDERED_HASHMAP_FOREACH(ext, extension_images) {
 
-                                const char *extension_setting = extension_setting_from_image(ext->type);
-                                if (!extension_setting)
-                                        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Image type '%s' not supported for extensions: %m", image_type_to_string(ext->type));
+                        const char *extension_setting = extension_setting_from_image(ext->type);
+                        if (!extension_setting)
+                                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Image type '%s' not supported for extensions: %m", image_type_to_string(ext->type));
 
-                                _cleanup_free_ char *extension_base_name = NULL;
-                                r = path_extract_filename(ext->path, &extension_base_name);
-                                if (r < 0)
-                                        return log_debug_errno(r, "Failed to extract basename from '%s': %m", ext->path);
+                        _cleanup_free_ char *extension_base_name = NULL;
+                        r = path_extract_filename(ext->path, &extension_base_name);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to extract basename from '%s': %m", ext->path);
 
-                                if (!strextend(&text,
+                        if (!strextend(&text,
+                                       "\n",
+                                       extension_setting,
+                                       ext->path,
+                                       /* With --force tell PID1 to avoid enforcing that the image <name> and
+                                        * extension-release.<name> have to match. */
+                                       !IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) &&
+                                           FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION) ?
+                                               ":x-systemd.relax-extension-release-check\n" :
                                                "\n",
-                                               extension_setting,
-                                               ext->path,
-                                               /* With --force tell PID1 to avoid enforcing that the image <name> and
-                                                * extension-release.<name> have to match. */
-                                               !IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) &&
-                                                   FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION) ?
-                                                       ":x-systemd.relax-extension-release-check\n" :
-                                                       "\n",
-                                               /* In PORTABLE= we list the 'main' image name for this unit
-                                                * (the image where the unit was extracted from), but we are
-                                                * stacking multiple images, so list those too. */
-                                               "LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n"))
-                                        return -ENOMEM;
-
-                                if (pinned_ext_image_policy && !IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME)) {
-                                        _cleanup_free_ char *policy_str = NULL;
-
-                                        r = image_policy_to_string(pinned_ext_image_policy, /* simplify= */ true, &policy_str);
-                                        if (r < 0)
-                                                return log_debug_errno(r, "Failed to serialize pinned image policy: %m");
+                                       /* In PORTABLE= we list the 'main' image name for this unit
+                                        * (the image where the unit was extracted from), but we are
+                                        * stacking multiple images, so list those too. */
+                                       "LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n"))
+                                return -ENOMEM;
 
-                                        if (!strextend(&text,
-                                                       "ExtensionImagePolicy=", policy_str, "\n"))
-                                                return -ENOMEM;
-                                }
+                        if (pinned_ext_image_policy && !IN_SET(ext->type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME)) {
+                                _cleanup_free_ char *policy_str = NULL;
 
-                                /* Look for image/version identifiers in the extension release files. We
-                                 * look for all possible IDs, but typically only 1 or 2 will be set, so
-                                 * the number of fields added shouldn't be too large. We prefix the DDI
-                                 * name to the value, so that we can add the same field multiple times and
-                                 * still be able to identify what applies to what. */
-                                r = append_release_log_fields(&text,
-                                                              ordered_hashmap_get(extension_releases, ext->name),
-                                                              IMAGE_SYSEXT,
-                                                              "PORTABLE_EXTENSION_NAME_AND_VERSION");
+                                r = image_policy_to_string(pinned_ext_image_policy, /* simplify= */ true, &policy_str);
                                 if (r < 0)
-                                        return r;
+                                        return log_debug_errno(r, "Failed to serialize pinned image policy: %m");
 
-                                r = append_release_log_fields(&text,
-                                                              ordered_hashmap_get(extension_releases, ext->name),
-                                                              IMAGE_CONFEXT,
-                                                              "PORTABLE_EXTENSION_NAME_AND_VERSION");
-                                if (r < 0)
-                                        return r;
+                                if (!strextend(&text,
+                                               "ExtensionImagePolicy=", policy_str, "\n"))
+                                        return -ENOMEM;
                         }
+
+                        /* Look for image/version identifiers in the extension release files. We
+                         * look for all possible IDs, but typically only 1 or 2 will be set, so
+                         * the number of fields added shouldn't be too large. We prefix the DDI
+                         * name to the value, so that we can add the same field multiple times and
+                         * still be able to identify what applies to what. */
+                        r = append_release_log_fields(&text,
+                                                      ordered_hashmap_get(extension_releases, ext->name),
+                                                      IMAGE_SYSEXT,
+                                                      "PORTABLE_EXTENSION_NAME_AND_VERSION");
+                        if (r < 0)
+                                return r;
+
+                        r = append_release_log_fields(&text,
+                                                      ordered_hashmap_get(extension_releases, ext->name),
+                                                      IMAGE_CONFEXT,
+                                                      "PORTABLE_EXTENSION_NAME_AND_VERSION");
+                        if (r < 0)
+                                return r;
+                }
         }
 
         r = write_string_file(dropin, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_SYNC);