summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-10-10 16:04:51 +0200
committerLennart Poettering <lennart@poettering.net>2023-10-11 15:56:08 +0200
commita81fe93e9532bd3286f21ca0696208eb474f686c (patch)
treec929ab46ada06773313b0574ed263b9af517ad67 /src
parentdissect: image size can be unset, suppres in JSON output then (diff)
downloadsystemd-a81fe93e9532bd3286f21ca0696208eb474f686c.tar.xz
systemd-a81fe93e9532bd3286f21ca0696208eb474f686c.zip
dissect: allow confext/sysext to be in the same image
This reworks the image discovery logic, and conceptually allows DDIs that are both confext and sysext to exist. Previously we'd only extract one type of exension data from a DDI, with this we allow to extract both if both exist. This doesn't add support for true "multi-modal" DDIs, that qualify as various things at once, it just lays some ground work that ensures we at least can dissect such images. This reworks 484d26dac1e8e543fc9e300e3c1fa36be0769f7d quite a bit. This changes systemd-dissect's JSON output, but given the version with the fields it changes/dops has never been released (as the above patch was merged post-v254) this shouldn't be an issue.
Diffstat (limited to 'src')
-rw-r--r--src/basic/os-util.h2
-rw-r--r--src/dissect/dissect.c86
-rw-r--r--src/shared/discover-image.c23
-rw-r--r--src/shared/discover-image.h14
-rw-r--r--src/shared/dissect-image.c105
-rw-r--r--src/shared/dissect-image.h4
-rw-r--r--src/sysext/sysext.c2
7 files changed, 143 insertions, 93 deletions
diff --git a/src/basic/os-util.h b/src/basic/os-util.h
index 11afc4c6ca..7cee3dd119 100644
--- a/src/basic/os-util.h
+++ b/src/basic/os-util.h
@@ -10,7 +10,9 @@ typedef enum ImageClass {
IMAGE_MACHINE,
IMAGE_PORTABLE,
IMAGE_SYSEXT,
+ _IMAGE_CLASS_EXTENSION_FIRST = IMAGE_SYSEXT, /* First "extension" image type, so that we can easily generically iterate through them */
IMAGE_CONFEXT,
+ _IMAGE_CLASS_EXTENSION_LAST = IMAGE_CONFEXT, /* Last "extension image type */
_IMAGE_CLASS_MAX,
_IMAGE_CLASS_INVALID = -EINVAL,
} ImageClass;
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 28cced4173..a03f9a64db 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -765,24 +765,40 @@ static void strv_pair_print(char **l, const char *prefix) {
printf("%*s %s=%s\n", (int) strlen(prefix), "", *p, *q);
}
-static int get_extension_scopes(DissectedImage *m, char ***ret_scopes) {
+static int get_extension_scopes(DissectedImage *m, ImageClass class, char ***ret_scopes) {
_cleanup_strv_free_ char **l = NULL;
- const char *e;
+ const char *e, *field_name;
+ char **release_data;
assert(m);
assert(ret_scopes);
+ switch (class) {
+
+ case IMAGE_SYSEXT:
+ release_data = m->sysext_release;
+ field_name = "SYSEXT_SCOPE";
+ break;
+
+ case IMAGE_CONFEXT:
+ release_data = m->confext_release;
+ field_name = "CONFEXT_SCOPE";
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
/* If there's no extension-release file its not a system extension. Otherwise the SYSEXT_SCOPE
* field for sysext images and the CONFEXT_SCOPE field for confext images indicates which scope
* it is for — and it defaults to "system" + "portable" if unset. */
- if (!m->extension_release) {
+
+ if (!release_data) {
*ret_scopes = NULL;
return 0;
}
- e = strv_env_pairs_get(m->extension_release, "SYSEXT_SCOPE");
- if (!e)
- e = strv_env_pairs_get(m->extension_release, "CONFEXT_SCOPE");
+ e = strv_env_pairs_get(release_data, field_name);
if (e)
l = strv_split(e, WHITESPACE);
else
@@ -843,7 +859,6 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
else if (r < 0)
return log_error_errno(r, "Failed to acquire image metadata: %m");
else if (arg_json_format_flags & JSON_FORMAT_OFF) {
- _cleanup_strv_free_ char **extension_scopes = NULL;
if (!sd_id128_is_null(m->image_uuid))
printf("Image UUID: %s\n", SD_ID128_TO_UUID_STRING(m->image_uuid));
@@ -860,15 +875,18 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
"OS Release:");
strv_pair_print(m->initrd_release,
"initrd R.:");
- strv_pair_print(m->extension_release,
- " Ext. Rel.:");
+ strv_pair_print(m->sysext_release,
+ " sysext R.:");
+ strv_pair_print(m->confext_release,
+ "confext R.:");
if (m->hostname ||
!sd_id128_is_null(m->machine_id) ||
!strv_isempty(m->machine_info) ||
!strv_isempty(m->os_release) ||
!strv_isempty(m->initrd_release) ||
- !strv_isempty(m->extension_release))
+ !strv_isempty(m->sysext_release) ||
+ !strv_isempty(m->confext_release))
putc('\n', stdout);
printf(" Use As: %s bootable system for UEFI\n", COLOR_MARK_BOOL(m->partitions[PARTITION_ESP].found));
@@ -881,26 +899,33 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
printf(" %s initrd\n",
COLOR_MARK_BOOL(!strv_isempty(m->initrd_release)));
- r = get_extension_scopes(m, &extension_scopes);
- if (r < 0)
- return log_error_errno(r, "Failed to parse scope: %m");
+ for (ImageClass c = _IMAGE_CLASS_EXTENSION_FIRST; c <= _IMAGE_CLASS_EXTENSION_LAST; c++) {
+ const char *string_class = image_class_to_string(c);
+ _cleanup_strv_free_ char **extension_scopes = NULL;
- const char *string_class = image_class_to_string(m->image_class);
- printf(" %s %s extension for system\n",
- COLOR_MARK_BOOL(strv_contains(extension_scopes, "system")), string_class);
- printf(" %s %s extension for initrd\n",
- COLOR_MARK_BOOL(strv_contains(extension_scopes, "initrd")), string_class);
- printf(" %s %s extension for portable service\n",
- COLOR_MARK_BOOL(strv_contains(extension_scopes, "portable")), string_class);
+ r = get_extension_scopes(m, c, &extension_scopes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse scopes: %m");
+
+ printf(" %s %s for system\n",
+ COLOR_MARK_BOOL(strv_contains(extension_scopes, "system")), string_class);
+ printf(" %s %s for portable service\n",
+ COLOR_MARK_BOOL(strv_contains(extension_scopes, "portable")), string_class);
+ printf(" %s %s for initrd\n",
+ COLOR_MARK_BOOL(strv_contains(extension_scopes, "initrd")), string_class);
+ }
putc('\n', stdout);
} else {
- _cleanup_(json_variant_unrefp) JsonVariant *mi = NULL, *osr = NULL, *irdr = NULL, *exr = NULL;
- _cleanup_strv_free_ char **extension_scopes = NULL;
+ _cleanup_strv_free_ char **sysext_scopes = NULL, **confext_scopes = NULL;
+
+ r = get_extension_scopes(m, IMAGE_SYSEXT, &sysext_scopes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse sysext scopes: %m");
- r = get_extension_scopes(m, &extension_scopes);
+ r = get_extension_scopes(m, IMAGE_CONFEXT, &confext_scopes);
if (r < 0)
- return log_error_errno(r, "Failed to parse scope: %m");
+ return log_error_errno(r, "Failed to parse confext scopes: %m");
Architecture a = dissected_image_architecture(m);
@@ -915,15 +940,18 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->machine_info), "machineInfo", JSON_BUILD_STRV_ENV_PAIR(m->machine_info)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->os_release), "osRelease", JSON_BUILD_STRV_ENV_PAIR(m->os_release)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->initrd_release), "initrdRelease", JSON_BUILD_STRV_ENV_PAIR(m->initrd_release)),
- JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->extension_release), "extensionRelease", JSON_BUILD_STRV_ENV_PAIR(m->extension_release)),
+ JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->sysext_release), "sysextRelease", JSON_BUILD_STRV_ENV_PAIR(m->sysext_release)),
+ JSON_BUILD_PAIR_CONDITION(!strv_isempty(m->confext_release), "confextRelease", JSON_BUILD_STRV_ENV_PAIR(m->confext_release)),
JSON_BUILD_PAIR("useBootableUefi", JSON_BUILD_BOOLEAN(m->partitions[PARTITION_ESP].found)),
JSON_BUILD_PAIR_CONDITION(m->has_init_system >= 0, "useBootableContainer", JSON_BUILD_BOOLEAN(m->has_init_system)),
JSON_BUILD_PAIR("useInitrd", JSON_BUILD_BOOLEAN(!strv_isempty(m->initrd_release))),
JSON_BUILD_PAIR("usePortableService", JSON_BUILD_BOOLEAN(strv_env_pairs_get(m->os_release, "PORTABLE_MATCHES"))),
- JSON_BUILD_PAIR("ExtensionType", JSON_BUILD_STRING(image_class_to_string(m->image_class))),
- JSON_BUILD_PAIR("useSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "system"))),
- JSON_BUILD_PAIR("useInitRDExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "initrd"))),
- JSON_BUILD_PAIR("usePortableExtension", JSON_BUILD_BOOLEAN(strv_contains(extension_scopes, "portable")))));
+ JSON_BUILD_PAIR("useSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "system"))),
+ JSON_BUILD_PAIR("useInitRDSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "initrd"))),
+ JSON_BUILD_PAIR("usePortableSystemExtension", JSON_BUILD_BOOLEAN(strv_contains(sysext_scopes, "portable"))),
+ JSON_BUILD_PAIR("useConfigurationExtension", JSON_BUILD_BOOLEAN(strv_contains(confext_scopes, "system"))),
+ JSON_BUILD_PAIR("useInitRDConfigurationExtension", JSON_BUILD_BOOLEAN(strv_contains(confext_scopes, "initrd"))),
+ JSON_BUILD_PAIR("usePortableConfigurationExtension", JSON_BUILD_BOOLEAN(strv_contains(confext_scopes, "portable")))));
if (r < 0)
return log_oom();
}
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index e407820e18..094337616d 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -101,7 +101,8 @@ static Image *image_free(Image *i) {
free(i->hostname);
strv_free(i->machine_info);
strv_free(i->os_release);
- strv_free(i->extension_release);
+ strv_free(i->sysext_release);
+ strv_free(i->confext_release);
return mfree(i);
}
@@ -1180,10 +1181,9 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy) {
case IMAGE_SUBVOLUME:
case IMAGE_DIRECTORY: {
- _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **extension_release = NULL;
+ _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **sysext_release = NULL, **confext_release = NULL;
+ _cleanup_free_ char *hostname = NULL, *path = NULL;
sd_id128_t machine_id = SD_ID128_NULL;
- _cleanup_free_ char *hostname = NULL;
- _cleanup_free_ char *path = NULL;
if (i->class == IMAGE_SYSEXT) {
r = extension_has_forbidden_content(i->path);
@@ -1223,16 +1223,20 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy) {
if (r < 0)
log_debug_errno(r, "Failed to read os-release in image, ignoring: %m");
- r = load_extension_release_pairs(i->path, i->class, i->name, /* relax_extension_release_check= */ false, &extension_release);
+ r = load_extension_release_pairs(i->path, IMAGE_SYSEXT, i->name, /* relax_extension_release_check= */ false, &sysext_release);
if (r < 0)
- log_debug_errno(r, "Failed to read extension-release in image, ignoring: %m");
+ log_debug_errno(r, "Failed to read sysext-release in image, ignoring: %m");
+
+ r = load_extension_release_pairs(i->path, IMAGE_CONFEXT, i->name, /* relax_extension_release_check= */ false, &confext_release);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read confext-release in image, ignoring: %m");
free_and_replace(i->hostname, hostname);
i->machine_id = machine_id;
strv_free_and_replace(i->machine_info, machine_info);
strv_free_and_replace(i->os_release, os_release);
- strv_free_and_replace(i->extension_release, extension_release);
-
+ strv_free_and_replace(i->sysext_release, sysext_release);
+ strv_free_and_replace(i->confext_release, confext_release);
break;
}
@@ -1271,7 +1275,8 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy) {
i->machine_id = m->machine_id;
strv_free_and_replace(i->machine_info, m->machine_info);
strv_free_and_replace(i->os_release, m->os_release);
- strv_free_and_replace(i->extension_release, m->extension_release);
+ strv_free_and_replace(i->sysext_release, m->sysext_release);
+ strv_free_and_replace(i->confext_release, m->confext_release);
break;
}
diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h
index edfb1412a4..bb046fae1e 100644
--- a/src/shared/discover-image.h
+++ b/src/shared/discover-image.h
@@ -45,7 +45,8 @@ typedef struct Image {
sd_id128_t machine_id;
char **machine_info;
char **os_release;
- char **extension_release;
+ char **sysext_release;
+ char **confext_release;
bool metadata_valid:1;
bool discoverable:1; /* true if we know for sure that image_find() would find the image given just the short name */
@@ -80,6 +81,17 @@ int image_read_metadata(Image *i, const ImagePolicy *image_policy);
bool image_in_search_path(ImageClass class, const char *root, const char *image);
+static inline char **image_extension_release(Image *image, ImageClass class) {
+ assert(image);
+
+ if (class == IMAGE_SYSEXT)
+ return image->sysext_release;
+ if (class == IMAGE_CONFEXT)
+ return image->confext_release;
+
+ return NULL;
+}
+
static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
assert(i);
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 278d2291a2..e63545312a 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -1665,7 +1665,8 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
strv_free(m->machine_info);
strv_free(m->os_release);
strv_free(m->initrd_release);
- strv_free(m->extension_release);
+ strv_free(m->confext_release);
+ strv_free(m->sysext_release);
return mfree(m);
}
@@ -3352,7 +3353,8 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
META_MACHINE_INFO,
META_OS_RELEASE,
META_INITRD_RELEASE,
- META_EXTENSION_RELEASE,
+ META_SYSEXT_RELEASE,
+ META_CONFEXT_RELEASE,
META_HAS_INIT_SYSTEM,
_META_MAX,
};
@@ -3361,15 +3363,16 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
[META_HOSTNAME] = "/etc/hostname\0",
[META_MACHINE_ID] = "/etc/machine-id\0",
[META_MACHINE_INFO] = "/etc/machine-info\0",
- [META_OS_RELEASE] = ("/etc/os-release\0"
- "/usr/lib/os-release\0"),
- [META_INITRD_RELEASE] = ("/etc/initrd-release\0"
- "/usr/lib/initrd-release\0"),
- [META_EXTENSION_RELEASE] = "extension-release\0", /* Used only for logging. */
+ [META_OS_RELEASE] = "/etc/os-release\0"
+ "/usr/lib/os-release\0",
+ [META_INITRD_RELEASE] = "/etc/initrd-release\0"
+ "/usr/lib/initrd-release\0",
+ [META_SYSEXT_RELEASE] = "sysext-release\0", /* String used only for logging. */
+ [META_CONFEXT_RELEASE] = "confext-release\0", /* ditto */
[META_HAS_INIT_SYSTEM] = "has-init-system\0", /* ditto */
};
- _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **initrd_release = NULL, **extension_release = NULL;
+ _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **initrd_release = NULL, **sysext_release = NULL, **confext_release = NULL;
_cleanup_close_pair_ int error_pipe[2] = PIPE_EBADF;
_cleanup_(rmdir_and_freep) char *t = NULL;
_cleanup_(sigkill_waitp) pid_t child = 0;
@@ -3379,12 +3382,10 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
int fds[2 * _META_MAX], r, v;
int has_init_system = -1;
ssize_t n;
- ImageClass image_class = IMAGE_SYSEXT;
BLOCK_SIGNALS(SIGCHLD);
assert(m);
- assert(image_class);
for (; n_meta_initialized < _META_MAX; n_meta_initialized ++) {
if (!paths[n_meta_initialized]) {
@@ -3439,40 +3440,46 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
switch (k) {
- case META_EXTENSION_RELEASE: {
- /* As per the os-release spec, if the image is an extension it will have a file
- * named after the image name in extension-release.d/ - we use the image name
- * and try to resolve it with the extension-release helpers, as sometimes
- * the image names are mangled on deployment and do not match anymore.
- * Unlike other paths this is not fixed, and the image name
- * can be mangled on deployment, so by calling into the helper
- * we allow a fallback that matches on the first extension-release
- * file found in the directory, if one named after the image cannot
- * be found first. */
- ImageClass class = IMAGE_SYSEXT;
- r = open_extension_release(t, IMAGE_SYSEXT, m->image_name, /* relax_extension_release_check= */ false, NULL, &fd);
- if (r == -ENOENT) {
- r = open_extension_release(t, IMAGE_CONFEXT, m->image_name, /* relax_extension_release_check= */ false, NULL, &fd);
- if (r >= 0)
- class = IMAGE_CONFEXT;
- }
+ case META_SYSEXT_RELEASE:
+ /* As per the os-release spec, if the image is an extension it will have a
+ * file named after the image name in extension-release.d/ - we use the image
+ * name and try to resolve it with the extension-release helpers, as
+ * sometimes the image names are mangled on deployment and do not match
+ * anymore. Unlike other paths this is not fixed, and the image name can be
+ * mangled on deployment, so by calling into the helper we allow a fallback
+ * that matches on the first extension-release file found in the directory,
+ * if one named after the image cannot be found first. */
+ r = open_extension_release(
+ t,
+ IMAGE_SYSEXT,
+ m->image_name,
+ /* relax_extension_release_check= */ false,
+ /* ret_path= */ NULL,
+ &fd);
+ if (r < 0)
+ fd = r;
+ break;
+
+ case META_CONFEXT_RELEASE:
+ /* As above */
+ r = open_extension_release(
+ t,
+ IMAGE_CONFEXT,
+ m->image_name,
+ /* relax_extension_release_check= */ false,
+ /* ret_path= */ NULL,
+ &fd);
if (r < 0)
fd = r;
- else {
- r = loop_write(fds[2*k+1], &class, sizeof(class));
- if (r < 0)
- goto inner_fail; /* Propagate the error to the parent */
- }
break;
- }
case META_HAS_INIT_SYSTEM: {
bool found = false;
FOREACH_STRING(init,
- "/usr/lib/systemd/systemd", /* systemd on /usr merged system */
- "/lib/systemd/systemd", /* systemd on /usr non-merged systems */
+ "/usr/lib/systemd/systemd", /* systemd on /usr/ merged system */
+ "/lib/systemd/systemd", /* systemd on /usr/ non-merged systems */
"/sbin/init") { /* traditional path the Linux kernel invokes */
r = chase(init, t, CHASE_PREFIX_ROOT, NULL, NULL);
@@ -3587,23 +3594,19 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
break;
- case META_EXTENSION_RELEASE: {
- ImageClass cl = IMAGE_SYSEXT;
- size_t nr;
+ case META_SYSEXT_RELEASE:
+ r = load_env_file_pairs(f, "sysext-release", &sysext_release);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read sysext release file of image: %m");
- errno = 0;
- nr = fread(&cl, 1, sizeof(cl), f);
- if (nr != sizeof(cl))
- log_debug_errno(errno_or_else(EIO), "Failed to read class of extension image: %m");
- else {
- image_class = cl;
- r = load_env_file_pairs(f, "extension-release", &extension_release);
- if (r < 0)
- log_debug_errno(r, "Failed to read extension release file of image: %m");
- }
+ break;
+
+ case META_CONFEXT_RELEASE:
+ r = load_env_file_pairs(f, "confext-release", &confext_release);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read confext release file of image: %m");
break;
- }
case META_HAS_INIT_SYSTEM: {
bool b = false;
@@ -3641,9 +3644,9 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
strv_free_and_replace(m->machine_info, machine_info);
strv_free_and_replace(m->os_release, os_release);
strv_free_and_replace(m->initrd_release, initrd_release);
- strv_free_and_replace(m->extension_release, extension_release);
+ strv_free_and_replace(m->sysext_release, sysext_release);
+ strv_free_and_replace(m->confext_release, confext_release);
m->has_init_system = has_init_system;
- m->image_class = image_class;
finish:
for (unsigned k = 0; k < n_meta_initialized; k++)
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index eb0841bd2e..21a0f22bcc 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -108,9 +108,9 @@ struct DissectedImage {
char **machine_info;
char **os_release;
char **initrd_release;
- char **extension_release;
+ char **confext_release;
+ char **sysext_release;
int has_init_system;
- ImageClass image_class;
};
struct MountOptions {
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index 784accc15d..becfbab44e 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -741,7 +741,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
host_os_release_version_id,
host_os_release_api_level,
in_initrd() ? "initrd" : "system",
- img->extension_release,
+ image_extension_release(img, arg_image_class),
arg_image_class);
if (r < 0)
return r;