mirror of
https://github.com/systemd/systemd
synced 2024-07-21 18:24:38 +00:00
Merge pull request #24263 from pothos/sysext-for-static-binaries
sysext: Support distribution-independent extensions with static binaries
This commit is contained in:
commit
e228d48b9e
|
@ -411,6 +411,18 @@
|
|||
determines the fallback hostname.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ARCHITECTURE=</varname></term>
|
||||
<listitem><para>A string that specifies which CPU architecture the userspace binaries require.
|
||||
The architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
|
||||
described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
The field is optional and should only be used when just single architecture is supported.
|
||||
It may provide redundant information when used in a GPT partition with a GUID type that already
|
||||
encodes the architecture. If this is not the case, the architecture should be specified in
|
||||
e.g., an extension image, to prevent an incompatible host from loading it.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>SYSEXT_LEVEL=</varname></term>
|
||||
|
||||
|
|
|
@ -115,12 +115,17 @@
|
|||
<para>A simple mechanism for version compatibility is enforced: a system extension image must carry a
|
||||
<filename>/usr/lib/extension-release.d/extension-release.<replaceable>$name</replaceable></filename>
|
||||
file, which must match its image name, that is compared with the host <filename>os-release</filename>
|
||||
file: the contained <varname>ID=</varname> fields have to match, as well as the
|
||||
<varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined, the
|
||||
<varname>VERSION_ID=</varname> field has to match instead. System extensions should not ship a
|
||||
<filename>/usr/lib/os-release</filename> file (as that would be merged into the host
|
||||
<filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable). The
|
||||
<filename>extension-release</filename> file follows the same format and semantics, and carries the same
|
||||
file: the contained <varname>ID=</varname> fields have to match unless <literal>_any</literal> is set
|
||||
for the extension. If the extension <varname>ID=</varname> is not <literal>_any</literal>, the
|
||||
<varname>SYSEXT_LEVEL=</varname> field (if defined) has to match. If the latter is not defined, the
|
||||
<varname>VERSION_ID=</varname> field has to match instead. If the extension defines the
|
||||
<varname>ARCHITECTURE=</varname> field and the value is not <literal>_any</literal> it has to match the kernel's
|
||||
architecture reported by <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
but the used architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
|
||||
described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
System extensions should not ship a <filename>/usr/lib/os-release</filename> file (as that would be merged
|
||||
into the host <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable).
|
||||
The <filename>extension-release</filename> file follows the same format and semantics, and carries the same
|
||||
content, as the <filename>os-release</filename> file of the OS, but it describes the resources carried
|
||||
in the extension image.</para>
|
||||
</refsect1>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "env-util.h"
|
||||
#include "extension-release.h"
|
||||
#include "log.h"
|
||||
|
@ -15,7 +16,7 @@ int extension_release_validate(
|
|||
const char *host_sysext_scope,
|
||||
char **extension_release) {
|
||||
|
||||
const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
|
||||
const char *extension_release_id = NULL, *extension_release_sysext_level = NULL, *extension_architecture = NULL;
|
||||
|
||||
assert(name);
|
||||
assert(!isempty(host_os_release_id));
|
||||
|
@ -48,13 +49,30 @@ int extension_release_validate(
|
|||
}
|
||||
}
|
||||
|
||||
/* When the architecture field is present and not '_any' it must match the host - for now just look at uname but in
|
||||
* the future we could check if the kernel also supports 32 bit or binfmt has a translator set up for the architecture */
|
||||
extension_architecture = strv_env_pairs_get(extension_release, "ARCHITECTURE");
|
||||
if (!isempty(extension_architecture) && !streq(extension_architecture, "_any") &&
|
||||
!streq(architecture_to_string(uname_architecture()), extension_architecture)) {
|
||||
log_debug("Extension '%s' is for architecture '%s', but deployed on top of '%s'.",
|
||||
name, extension_architecture, architecture_to_string(uname_architecture()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
extension_release_id = strv_env_pairs_get(extension_release, "ID");
|
||||
if (isempty(extension_release_id)) {
|
||||
log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
|
||||
log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s' or be '_any'",
|
||||
name, host_os_release_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A sysext with no host OS dependency (static binaries or scripts) can match
|
||||
* '_any' host OS, and VERSION_ID or SYSEXT_LEVEL are not required anywhere */
|
||||
if (streq(extension_release_id, "_any")) {
|
||||
log_debug("Extension '%s' matches '_any' OS.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!streq(host_os_release_id, extension_release_id)) {
|
||||
log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
|
||||
name, extension_release_id, host_os_release_id);
|
||||
|
|
|
@ -712,6 +712,13 @@ EOF
|
|||
chmod +x "$initdir/opt/script1.sh"
|
||||
echo MARKER=1 >"$initdir/usr/lib/systemd/system/other_file"
|
||||
mksquashfs "$initdir" "$oldinitdir/usr/share/app1.raw" -noappend
|
||||
|
||||
export initdir="$TESTDIR/app-nodistro"
|
||||
mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system"
|
||||
( echo "ID=_any"
|
||||
echo "ARCHITECTURE=_any" ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro"
|
||||
echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file"
|
||||
mksquashfs "$initdir" "$oldinitdir/usr/share/app-nodistro.raw" -noappend
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -305,6 +305,7 @@ systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.r
|
|||
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
|
||||
systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
|
||||
systemd-run -P --property ExtensionImages=/usr/share/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||
cat >/run/systemd/system/testservice-50e.service <<EOF
|
||||
[Service]
|
||||
MountAPIVFS=yes
|
||||
|
@ -323,17 +324,19 @@ systemctl start testservice-50e.service
|
|||
systemctl is-active testservice-50e.service
|
||||
|
||||
# ExtensionDirectories will set up an overlay
|
||||
mkdir -p "${image_dir}/app0" "${image_dir}/app1"
|
||||
mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
|
||||
systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0"
|
||||
systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1"
|
||||
systemd-dissect --mount /usr/share/app-nodistro.raw "${image_dir}/app-nodistro"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
|
||||
systemd-run -P --property ExtensionDirectories="${image_dir}/app-nodistro" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||
cat >/run/systemd/system/testservice-50f.service <<EOF
|
||||
[Service]
|
||||
MountAPIVFS=yes
|
||||
|
|
Loading…
Reference in a new issue