diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml
index 14aab94dc9..6bda5f4fc6 100644
--- a/man/systemd-sysext.xml
+++ b/man/systemd-sysext.xml
@@ -55,10 +55,9 @@
Files and directories contained in the extension images outside of the /usr/
and /opt/ hierarchies are not merged, and hence have no effect
- when included in a system extension image (with the exception of /etc/os-release,
- see below). In particular, files in the /etc/ and /var/
- included in a system extension image will not appear in the respective hierarchies
- after activation.
+ when included in a system extension image. In particular, files in the /etc/ and
+ /var/ included in a system extension image will not appear in
+ the respective hierarchies after activation.
System extension images are strictly read-only, and the host /usr/ and
/opt/ hierarchies become read-only too while they are activated.
@@ -111,13 +110,17 @@
Note that there is no concept of enabling/disabling installed system extension images: all
installed extension images are automatically activated at boot.
- A simple mechanism for version compatibility is enforced: a system extension image may carry an
- /etc/os-release file that is compared with the host os-release
+ A simple mechanism for version compatibility is enforced: a system extension image must carry a
+ /usr/lib/extension-release.d/extension-release.$name
+ file, which must match its image name, that is compared with the host os-release
file: the contained ID= fields have to match, as well as the
- SYSEXT_LEVEL= field (if defined). If the latter is not defined the
+ SYSEXT_LEVEL= field (if defined). If the latter is not defined, the
VERSION_ID= field has to match instead. System extensions should not ship a
/usr/lib/os-release file (as that would be merged into the host
- /usr/ tree, overriding the host OS version data, which is not desirable).
+ /usr/ tree, overriding the host OS version data, which is not desirable). The
+ extension-release file follows the same format and semantics, and carries the same
+ content, as the os-release file of the OS, but it describes the resources carried
+ in the extension image.
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index c12f40c160..8a8cd7535e 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -441,7 +441,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
/* Let's now mount all images */
HASHMAP_FOREACH(img, images) {
_cleanup_free_ char *p = NULL,
- *extension_os_release_id = NULL, *extension_os_release_version_id = NULL, *extension_os_release_sysext_level = NULL;
+ *extension_release_id = NULL, *extension_release_version_id = NULL, *extension_release_sysext_level = NULL;
p = path_join(workspace, "extensions", img->name);
if (!p)
@@ -535,36 +535,39 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
"Extension image contains /usr/lib/os-release file, which is not allowed (it may carry /etc/os-release), refusing.");
/* Now that we can look into the extension image, let's see if the OS version is compatible */
- r = parse_os_release(
+ r = parse_extension_release(
p,
- "ID", &extension_os_release_id,
- "VERSION_ID", &extension_os_release_version_id,
- "SYSEXT_LEVEL", &extension_os_release_sysext_level,
+ img->name,
+ "ID", &extension_release_id,
+ "VERSION_ID", &extension_release_version_id,
+ "SYSEXT_LEVEL", &extension_release_sysext_level,
NULL);
- if (r == -ENOENT)
- log_notice_errno(r, "Extension '%s' carries no os-release data, not checking for version compatibility.", img->name);
- else if (r < 0)
+ if (r == -ENOENT) {
+ log_notice_errno(r, "Extension '%s' carries no extension-release data, ignoring extension.", img->name);
+ n_ignored++;
+ continue;
+ } else if (r < 0)
return log_error_errno(r, "Failed to acquire 'os-release' data of extension '%s': %m", img->name);
else {
- if (!streq_ptr(host_os_release_id, extension_os_release_id)) {
+ if (!streq_ptr(host_os_release_id, extension_release_id)) {
log_notice("Extension '%s' is for OS '%s', but running on '%s', ignoring extension.",
- img->name, strna(extension_os_release_id), strna(host_os_release_id));
+ img->name, strna(extension_release_id), strna(host_os_release_id));
n_ignored++;
continue;
}
/* If the extension has a sysext API level declared, then it must match the host API level. Otherwise, compare OS version as a whole */
- if (extension_os_release_sysext_level) {
- if (!streq_ptr(host_os_release_sysext_level, extension_os_release_sysext_level)) {
+ if (extension_release_sysext_level) {
+ if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) {
log_notice("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s', ignoring extension.",
- img->name, extension_os_release_sysext_level, strna(host_os_release_sysext_level));
+ img->name, extension_release_sysext_level, strna(host_os_release_sysext_level));
n_ignored++;
continue;
}
} else {
- if (!streq_ptr(host_os_release_version_id, extension_os_release_version_id)) {
+ if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) {
log_notice("Extension '%s' is for OS version '%s', but running on OS version '%s', ignoring extension.",
- img->name, extension_os_release_version_id, strna(host_os_release_version_id));
+ img->name, extension_release_version_id, strna(host_os_release_version_id));
n_ignored++;
continue;
}