]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #31987 from flatcar-hub/krnowak/usr-perm-check
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Apr 2024 09:14:35 +0000 (11:14 +0200)
committerGitHub <noreply@github.com>
Mon, 22 Apr 2024 09:14:35 +0000 (11:14 +0200)
sysext: Fix issues with merged hierarchy mode

85 files changed:
.github/advanced-issue-labeler.yml
.github/labeler.yml
.github/workflows/mkosi.yml
NEWS
TODO
docs/ENVIRONMENT.md
man/custom-entities.ent.in
man/networkd.conf.xml
man/org.freedesktop.hostname1.xml
man/org.freedesktop.portable1.xml
man/portablectl.xml
man/sd_event_add_inotify.xml
man/sd_id128_get_machine.xml
man/systemd-gpt-auto-generator.xml
man/systemd-measure.xml
man/systemd-stub.xml
man/systemd-vmspawn.xml
man/systemd.network.xml
man/ukify.xml
mkosi.conf
mkosi.images/system/mkosi.conf.d/10-arch/mkosi.conf
mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.build.chroot
mkosi.images/system/mkosi.conf.d/10-centos-fedora/mkosi.conf
mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-groups.conf [new file with mode: 0644]
mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-users.conf [new file with mode: 0644]
mkosi.images/system/mkosi.conf.d/10-debian-ubuntu/mkosi.conf
mkosi.images/system/mkosi.conf.d/10-opensuse/mkosi.conf
mkosi.images/system/mkosi.postinst.chroot
po/id.po
src/basic/log.c
src/basic/log.h
src/basic/virt.c
src/boot/efi/cpio.c
src/boot/efi/stub.c
src/boot/measure.c
src/fundamental/uki.c
src/fundamental/uki.h
src/libsystemd-network/radv-internal.h
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-ndisc-ra.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-event/event-source.h
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-id128/sd-id128.c
src/libsystemd/sd-journal/journal-verify.c
src/libsystemd/sd-journal/sd-journal.c
src/libsystemd/sd-journal/test-journal-interleaving.c
src/network/networkd-dns.c
src/network/networkd-gperf.gperf
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
src/network/networkd.conf
src/pcrlock/pcrlock.c
src/portable/portable.c
src/resolve/resolved-dnstls-openssl.c
src/shared/clock-util.c
src/shared/discover-image.c
src/shared/openssl-util.c
src/shared/openssl-util.h
src/shared/tests.c
src/shared/tests.h
src/shared/tpm2-util.c
src/shared/vpick.c
src/shared/vpick.h
src/systemd/sd-event.h
src/systemd/sd-id128.h
src/systemd/sd-radv.h
src/test/test-bpf-firewall.c
src/test/test-bpf-restrict-fs.c
src/test/test-execute.c
src/test/test-fdset.c
src/test/test-id128.c
src/test/test-macro.c
src/test/test-vpick.c
src/timedate/timedated.c
src/ukify/ukify.py
src/vmspawn/vmspawn.c
src/vpick/vpick-tool.c
test/test-network/systemd-networkd-tests.py
test/units/testsuite-29.sh

index bee39e8285222dbb5c55e447dc0d5aca5d6a9171..4d70058938aa1fec385e8655a2bccfe4f17690cc 100644 (file)
@@ -64,10 +64,10 @@ policy:
           - name: kernel-install
             keys: ['kernel-install']
 
-          - name: logind
+          - name: login
             keys: ['systemd-logind', 'loginctl', 'pam_systemd']
 
-          - name: machined
+          - name: machine
             keys: ['systemd-machined', 'machinectl']
 
           - name: modules-load
index e8952dc82a6dbd153e1f3aa7c854665442d1c8d5..ed4bf8292443ca9afabea0ac93370d449f20a970 100644 (file)
@@ -66,10 +66,7 @@ journal-remote:
     - any-glob-to-any-file: 'src/journal-remote/*'
 login:
   - changed-files:
-    - any-glob-to-any-file: '**/sd-login*/**'
-logind:
-  - changed-files:
-    - any-glob-to-any-file: 'src/login/*'
+    - any-glob-to-any-file: ['src/login/*', '**/sd-login*/**']
 meson:
   - changed-files:
     - any-glob-to-any-file: ['meson_options.txt', '**/meson.build']
index 56f62e67ea7247604154f8ba5e43b6eb9fc8a08a..8110395262ba5332dff50a5e28cc51fc1300114d 100644 (file)
@@ -74,7 +74,7 @@ jobs:
 
     steps:
     - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
-    - uses: systemd/mkosi@236784dbb597321eedab50cef06cc49f92c57293
+    - uses: systemd/mkosi@6ab7d9f09f8f2633f4b7c777a04e62e109486e2f
 
     # Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
     # immediately, we remove the files in the background. However, we first move them to a different location
diff --git a/NEWS b/NEWS
index a454c0d1d4241e165c59c3e9bb160b577e846d31..d990d34cd80b187d8315f8a7adb6f3b59f9c34a8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,7 +26,7 @@ CHANGES WITH 256-rc1:
           or /efi/ hierarchies in /etc/fstab. This is to prevent the generator
           from interfering with systems where the ESP is explicitly configured
           to be mounted at some path, for example /boot/efi/ (this type of
-          setup is obsolete but still commonly found).
+          setup is obsolete, but still commonly found).
 
         * The behavior of systemd-sleep and systemd-homed has been updated to
           freeze user sessions when entering the various sleep modes or when
@@ -72,23 +72,23 @@ CHANGES WITH 256-rc1:
           embedded in the file name. The files are ordered by version and
           the newest one is selected.
 
-          systemd-nspawn --image=/--directory=, systemd-dissect, and the
-          RootDirectory=, RootImage=, ExtensionImages=, and
+          systemd-nspawn --image=/--directory=, systemd-dissect, systemd-portabled,
+          and the RootDirectory=, RootImage=, ExtensionImages=, and
           ExtensionDirectories= settings for units now support the vpick
           protocol and allow the latest version to be selected automatically if
           a "*.v/" directory is specified as the source.
 
-        * Encrypted service credentials may now be made accessible to
+        * Encrypted service credentials can now be made accessible to
           unprivileged users. systemd-creds gained new options --user/--uid=
           for encrypting/decrypting a credential for a specific user.
 
         * New command-line tool 'importctl' to download, import, and export
           disk images via systemd-importd is added with the following verbs:
           pull-tar, pull-raw, import-tar, import-raw, import-fs, export-tar,
-          export-raw, list-transfers, cancel-transfer. This functionality was
-          previously available in "machinectl", where it was exclusively for
-          machine image. The new "importctl" generalizes this for sysext,
-          confext, portable service images, too.
+          export-raw, list-transfers, and cancel-transfer. This functionality
+          was previously available in "machinectl", where it was used
+          exclusively for machine images. The new "importctl" generalizes this
+          for sysext, confext, and portable service images.
 
         Service Management:
 
@@ -97,9 +97,9 @@ CHANGES WITH 256-rc1:
           enabled by default in the initrd.
 
         * New unit setting WantsMountsFor= has been added. It is analogous to
-          RequiresMountsFor=, but with a Wants= dependency instead of
-          Requires=. This new logic is used in various places where mounts were
-          added as dependencies for other settings (WorkingDirectory=-…,
+          RequiresMountsFor=, but creates a Wants= dependency instead of
+          Requires=. This new logic is now used in various places where mounts
+          were added as dependencies for other settings (WorkingDirectory=-…,
           PrivateTmp=yes, cryptsetup lines with 'nofail').
 
         * New unit setting MemoryZSwapWriteback= can be used to control the new
@@ -107,9 +107,11 @@ CHANGES WITH 256-rc1:
 
         * The manager gained a org.freedesktop.systemd1.StartAuxiliaryScope()
           D-Bus method to devolve some processes from a service into a new
-          scope.  This new scope will remain even if the original service unit
-          is restarted. Control group properties of the new scope are copied
-          from the originating unit, so various limits are retained.
+          scope. This new scope will remain running, even when the original
+          service unit is restarted or stopped. This allows a service unit to
+          split out some worker processes which need to continue running.
+          Control group properties of the new scope are copied from the
+          originating unit, so various limits are retained.
 
         * Units now expose properties EffectiveMemoryMax=,
           EffectiveMemoryHigh=, and EffectiveTasksMax=, which report the
@@ -136,26 +138,27 @@ CHANGES WITH 256-rc1:
           system credential.
 
         * The systemd binary will no longer chainload sysvinit's "telinit"
-          binary when called under the init/telinit name on a system that
-          isn't booted with systemd. This previously has been supported to make
-          sure a distribution that has both init systems installed can be
-          reasonably switched from one to the other via a simple
-          reboot. Distributions apparently have lost interest in this, and the
-          functionality has not been supported on the primary distribution this
-          was still intended for for a longer time, and hence has been removed
-          now.
-
-        * A new concept called "capsules" has been introduced. "Capsules"
-          encapsulate additional per-user service managers, whose users are
-          transient and are only defined as long as the service manager
-          is running (implemented via DynamicUser=1). These service managers run
-          off home directories defined in /var/lib/capsules/<name>, where
-          <name> is a the capsule's name. These home directories can contain
-          regular per-user services and other units. A capsule is started via a
-          simple "systemctl start capsule@<name>.service". See the
-          capsule@.service(5) man page for further details. Various systemd
-          tools (including, and most importantly, systemctl and systemd-run)
-          have been updated to interact with capsules via the new
+          binary when called under the init/telinit name on a system that isn't
+          booted with systemd. This previously has been supported to make sure
+          a distribution that has both init systems installed can reasonably
+          switch from one to the other via a simple reboot. Distributions
+          apparently have lost interest in this, and the functionality has not
+          been supported on the primary distribution this was still intended
+          for for a long time, and hence has been removed now.
+
+        * A new concept called "capsules" has been introduced. "Capsules" wrap
+          additional per-user service managers, whose users are transient and
+          are only defined as long as the service manager is running. (This is
+          implemented via DynamicUser=1), allowing a user manager to be used to
+          manager a group of processes without needing to create an actual user
+          account. These service managers run with home directories of
+          /var/lib/capsules/<capsule-name> and can contain regular services and
+          other units. A capsule is started via a simple "systemctl start
+          capsule@<name>.service". See the capsule@.service(5) man page for
+          further details.
+
+          Various systemd tools (including, and most importantly, systemctl and
+          systemd-run) have been updated to interact with capsules via the new
           "--capsule="/"-C" switch.
 
         * .socket units gained a new setting PassFileDescriptorsToExec=, taking
@@ -163,7 +166,8 @@ CHANGES WITH 256-rc1:
           encapsulates are passed to the ExecStartPost=, ExecStopPre=,
           ExecStopPost= using the usual $LISTEN_FDS interface. This may be used
           for doing additional initializations on the sockets once they are
-          allocated (for example, install an additional eBPF program on them).
+          allocated. (For example, to install an additional eBPF program on
+          them).
 
         * The .socket setting MaxConnectionsPerSource= (which so far put a
           limit on concurrent connections per IP in Accept=yes socket units),
@@ -173,13 +177,13 @@ CHANGES WITH 256-rc1:
           services in a simple Accept=yes mode.
 
         * The service manager will now maintain a counter of soft reboot cycles
-          the system went through so far. It may be queried via the D-Bus APIs.
+          the system went through. It may be queried via the D-Bus APIs.
 
         * systemd's execution logic now supports the new pidfd_spawn() API
           introduced by glibc 2.39, which allows us to invoke a subprocess in a
           target cgroup and get a pidfd back in a single operation.
 
-        * systemd/PID 1 will now send an additional sd_notify() message to its
+        * systemd/PID 1 will now send an additional sd_notify() message to its
           supervising VMM or container manager reporting the selected hostname
           ("X_SYSTEMD_HOSTNAME=") and machine ID ("X_SYSTEMD_MACHINE_ID=") at
           boot. Moreover, the service manager will send additional sd_notify()
@@ -189,9 +193,10 @@ CHANGES WITH 256-rc1:
           reports "ssh-access.target" being reached a VMM/container manager
           knows it can now connect to the system via SSH. Finally, a new
           sd_notify() message ("X_SYSTEMD_SIGNALS_LEVEL=2") is sent the moment
-          PID 1 successfully completed installation of its various UNIX process
-          signal handlers (i.e. the moment where SIGRTMIN+4 sent to PID 1 will
-          start to have the effect of shutting down the system cleanly).
+          PID 1 has successfully completed installation of its various UNIX
+          process signal handlers (i.e. the moment where SIGRTMIN+4 sent to
+          PID 1 will start to have the effect of shutting down the system
+          cleanly).
 
         Journal:
 
@@ -603,6 +608,12 @@ CHANGES WITH 256-rc1:
           --ssh-key-type= to optionally set up transient SSH keys to pass to the
           invoked VMs in order to be able to SSH into them once booted.
 
+        * systemd-vmspawn will now enable various "HyperV enlightenments" and
+          the "VM Generation ID" on the VMs.
+
+        * A new environment variable $SYSTEMD_VMSPAWN_QEMU_EXTRA may carry
+          additional qemu command line options to pass to qemu.
+
         systemd-repart:
 
         * systemd-repart gained new options --generate-fstab= and
@@ -638,6 +649,10 @@ CHANGES WITH 256-rc1:
           sd_journal_stream_fd() but creates a log stream targeted at a
           specific log namespace.
 
+        * The sd-id128 API gained a new API call
+          sd_id128_get_invocation_app_specific() for acquiring an app-specific
+          ID that is derived from the service invocation ID.
+
         systemd-cryptsetup/systemd-cryptenroll:
 
         * systemd-cryptenroll can now enroll directly with a PKCS11 public key
diff --git a/TODO b/TODO
index 1c77f9ffc5c1db32df0d783fb8a2a8e312a1330c..548a7c31fc5292a05f5ae7eb79726088d1d755c8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -130,6 +130,10 @@ Deprecations and removals:
 
 Features:
 
+* systemd-repart should probably enable btrfs' "temp_fsid" feature for all file
+  systems it creates, as we have no interest in RAID for repart, and it should
+  make sure that we can mount them trivially everywhere.
+
 * systemd-nspawn should get the same SSH key support that vmspawn now has.
 
 * insert the new pidfs inode number as a third field into PidRef, so that
@@ -325,10 +329,7 @@ Features:
     PCRs.
 
 * vmspawn:
-  - enable hyperv extension by default (https://www.qemu.org/docs/master/system/i386/hyperv.html)
-  - register with machined
   - run in scope unit when invoked from command line, and machined registration is off
-  - support --directory= via virtiofs
   - sd_notify support
   - --ephemeral support
   - --read-only support
index 961601c72e0dc76f3215d489667a65ff02d00a1d..8068d0d33cf214a1803c688aabbb9a347fcb24d3 100644 (file)
@@ -191,6 +191,9 @@ All tools:
   expected format is six groups of two hexadecimal digits separated by colons,
   e.g. `SYSTEMD_VMSPAWN_NETWORK_MAC=12:34:56:78:90:AB`
 
+* `$SYSTEMD_VMSPAWN_QEMU_EXTRA=…` â€“ may contain additional command line
+  arguments to append the qemu command line.
+
 `systemd-logind`:
 
 * `$SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1` â€” if set, report that
index c82e2b8d8f6ece720cb3534b0fbc6420bce21689..8dfc1eb98c7c49403d03d19012b4c9256ca78477 100644 (file)
@@ -19,3 +19,4 @@
 <!ENTITY DEFAULT_USER_TIMEOUT "{{DEFAULT_USER_TIMEOUT_SEC}} s">
 <!ENTITY DEFAULT_KEYMAP "{{SYSTEMD_DEFAULT_KEYMAP}}">
 <!ENTITY fedora_latest_version "40">
+<!ENTITY fedora_cloud_release "1.10">
index 8820fcc507da1d02d0d708056a0d09b5ec700ab2..843636fd4fdeccba6a0b795c4dbcba1f6f4667de 100644 (file)
         <xi:include href="version-info.xml" xpointer="v254"/>
         </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>UseDomains=</varname></term>
+        <listitem>
+          <para>Specifies the network- and protocol-independent default value for the same settins in
+          [IPv6AcceptRA], [DHCPv4], and [DHCPv6] sections below. Takes a boolean, or the special value
+          <option>route</option>. See the same setting in
+          <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          Defaults to <literal>no</literal>.</para>
+
+          <xi:include href="version-info.xml" xpointer="v256"/>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>[IPv6AcceptRA] Section Options</title>
+
+    <para>This section configures the default setting of the Neighbor Discovery. The following options are
+    available in the [IPv6AcceptRA] section:</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>UseDomains=</varname></term>
+        <listitem>
+          <para>Specifies the network-independent default value for the same setting in the [IPv6AcceptRA]
+          section in
+          <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          Takes a boolean, or the special value <option>route</option>. When unspecified, the value specified
+          in the [Network] section in
+          <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+          which defaults to <literal>no</literal>, will be used.</para>
+
+          <xi:include href="version-info.xml" xpointer="v256"/>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
@@ -260,11 +297,9 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
 
       <varlistentry>
         <term><varname>UseDomains=</varname></term>
-          <listitem><para>Specifies the default value for per-network <varname>UseDomains=</varname>.
-          Takes a boolean. See for details in
-          <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-          Defaults to <literal>no</literal>.</para>
-          
+        <listitem>
+          <para>Same as the one in the [IPv6AcceptRA] section, but applied for DHCPv4 protocol.</para>
+
           <xi:include href="version-info.xml" xpointer="v256"/>
         </listitem>
       </varlistentry>
@@ -310,12 +345,9 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00</programlisting>
 
     <variablelist class='network-directives'>
       <varlistentry>
-        <term><varname>PersistLeases=</varname></term>
+        <term><varname>UseDomains=</varname></term>
         <listitem>
-          <para>Specifies the default value for per-network <varname>PersistLeases=</varname>.
-          Takes a boolean. See for details in
-          <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-          Defaults to <literal>yes</literal>.</para>
+          <para>Same as the one in the [IPv6AcceptRA] section, but applied for DHCPv4 protocol.</para>
 
           <xi:include href="version-info.xml" xpointer="v256"/>
         </listitem>
index 61d9831ca6b8a5aaaccaa8a6c7b5fe4165aa3149..d16ae9ab1c276fc458f09f611f8ce717f27fc942 100644 (file)
@@ -108,20 +108,6 @@ node /org/freedesktop/hostname1 {
 };
     </programlisting>
 
-    <!--method GetHardwareSerial is not documented!-->
-
-    <!--property OperatingSystemSupportEnd is not documented!-->
-
-    <!--property HardwareVendor is not documented!-->
-
-    <!--property HardwareModel is not documented!-->
-
-    <!--property FirmwareVersion is not documented!-->
-
-    <!--property FirmwareVendor is not documented!-->
-
-    <!--property FirmwareDate is not documented!-->
-
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.hostname1"/>
@@ -299,6 +285,22 @@ node /org/freedesktop/hostname1 {
     <constant>UINT32_MAX</constant> otherwise. See <citerefentry project="man-pages"><refentrytitle>vsock</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
     details.</para>
 
+    <para><varname>OperatingSystemSupportEnd</varname> exposes when the OS' vendor support ends, if this
+    information is known. It's an unsigned 64bit value, in Âµs since the UNIX epoch, UTC. If this information
+    is not known carries the value 2^64-1, i.e. <constant>UINT64_MAX</constant>.</para>
+
+    <para><varname>HardwareVendor</varname> and <varname>HardwareModel</varname> expose information about the
+    vendor of the hardware of the system. If no such information can be determined these properties are set
+    to empty strings.</para>
+
+    <para><varname>FirmwareVersion</varname> and <varname>FirmwareVendor</varname> expose information about
+    the system's firmware, i.e. a version string and a vendor name. If no such information can be determined
+    these properties are set to empty strings.</para>
+
+    <para><varname>FirmwareDate</varname> exposes the firmware build date, if that information is known. It's
+    an unsigned 64bit value, in Âµs since the UNIX epoch, UTC. If not known
+    <constant>UNIT64_MAX</constant>.</para>
+
     <refsect2>
       <title>Methods</title>
 
@@ -333,6 +335,10 @@ node /org/freedesktop/hostname1 {
       requires root privileges, and this method allows access to unprivileged clients through the polkit
       framework.</para>
 
+      <para><function>GetHardwareSerial()</function> returns the "hardware serial" as exposed by the kernel
+      based on DMI information. Reading the file directly requires root privileges, and this method allows
+      access to unprivileged clients through the polkit framework.</para>
+
       <para><function>Describe()</function> returns a JSON representation of all properties in one.</para>
     </refsect2>
 
index c68995d95248f797e108e98071fc1d527bafb532..4de3da2905dfe9567338dc46c46fb184b273c2aa 100644 (file)
@@ -259,6 +259,9 @@ node /org/freedesktop/portable1 {
       on the system. Note that this method returns only after all the listed operations are completed,
       and due to the I/O involved it might take some time.</para>
 
+      <xi:include href="vpick.xml" xpointer="image"/>
+      <xi:include href="vpick.xml" xpointer="directory"/>
+
       <para><function>AttachImageWithExtensions()</function> attaches a portable image to the system.
       This method is a superset of <function>AttachImage()</function> with the addition of
       a list of extensions as input parameter, which will be overlaid on top of the main
index 5e88eb309dc4cc65e446090e2a60c6637821dd35..92d8ff03aa76fc7c82b84295677b399c36fe8b31 100644 (file)
         immediately started (blocking operation unless <option>--no-block</option> is passed) and/or enabled after
         attaching the image.</para>
 
+        <xi:include href="vpick.xml" xpointer="image"/>
+        <xi:include href="vpick.xml" xpointer="directory"/>
         <xi:include href="version-info.xml" xpointer="v239"/>
         </listitem>
       </varlistentry>
         <para>Note that the same extensions have to be specified, in the same order, when attaching
         and detaching.</para>
 
+        <xi:include href="vpick.xml" xpointer="image"/>
+        <xi:include href="vpick.xml" xpointer="directory"/>
         <xi:include href="version-info.xml" xpointer="v249"/></listitem>
       </varlistentry>
 
index 69c51948992ad138f73ecbe19a00096774e65a1f..ed26c8ac96ecf1deab7afe7fd69dab1cb0a168f9 100644 (file)
@@ -19,6 +19,7 @@
     <refname>sd_event_add_inotify</refname>
     <refname>sd_event_add_inotify_fd</refname>
     <refname>sd_event_source_get_inotify_mask</refname>
+    <refname>sd_event_source_get_inotify_path</refname>
     <refname>sd_event_inotify_handler_t</refname>
 
     <refpurpose>Add an "inotify" file system inode event source to an event loop</refpurpose>
       <funcprototype>
         <funcdef>int <function>sd_event_source_get_inotify_mask</function></funcdef>
         <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
-        <paramdef>uint32_t *<parameter>mask</parameter></paramdef>
+        <paramdef>uint32_t *<parameter>ret</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_event_source_get_inotify_path</function></funcdef>
+        <paramdef>sd_event_source *<parameter>source</parameter></paramdef>
+        <paramdef>const char **<parameter>ret</parameter></paramdef>
       </funcprototype>
 
     </funcsynopsis>
     event source created previously with <function>sd_event_add_inotify()</function>. It takes the event source object
     as the <parameter>source</parameter> parameter and a pointer to a <type>uint32_t</type> variable to return the mask
     in.</para>
+
+    <para><function>sd_event_source_get_inotify_path()</function> retrieves the target path of the configured
+    inotify watch of an event source created previously with <function>sd_event_add_inotify()</function>. It
+    takes the event source object as the <parameter>source</parameter> parameter and a pointer to a
+    <type>const char **</type> variable to return the path in. The caller must not free the returned path.
+    </para>
   </refsect1>
 
   <refsect1>
         <varlistentry>
           <term><constant>-ESTALE</constant></term>
 
-          <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem>
+            <para>Returned by <function>sd_event_source_add_inotify()</function> or
+            <function>sd_event_source_add_inotify_fd()</function> when the event loop is already terminated.
+            Returned by <function>sd_event_source_get_inotify_path()</function> when no active inode data is
+            assigned to the event source, e.g. when the event source is disabled.</para>
+          </listitem>
 
         </varlistentry>
 
         <varlistentry>
           <term><constant>-EBADF</constant></term>
 
-          <listitem><para>The passed file descriptor is not valid.</para>
+          <listitem><para>The passed file descriptor is not valid.</para></listitem>
 
-          <xi:include href="version-info.xml" xpointer="v250"/></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><constant>-ENOSYS</constant></term>
 
-          <listitem><para><function>sd_event_add_inotify_fd()</function> was called without
-          <filename>/proc/</filename> mounted.</para>
+          <listitem>
+            <para><function>sd_event_add_inotify_fd()</function> or
+            <function>sd_event_source_get_inotify_path()</function> was called without
+            <filename>/proc/</filename> mounted.</para>
+          </listitem>
 
-          <xi:include href="version-info.xml" xpointer="v250"/></listitem>
         </varlistentry>
 
       </variablelist>
     <function>sd_event_add_inotify()</function>, and
     <function>sd_event_source_get_inotify_mask()</function> were added in version 239.</para>
     <para><function>sd_event_add_inotify_fd()</function> was added in version 250.</para>
+    <para><function>sd_event_source_get_inotify_path()</function> was added in version 256.</para>
   </refsect1>
 
   <refsect1>
index 6904f2953c6709692a8bf1edb823a60009cf5fae..59f3266e6feedbb929c679b371b08836f44734b5 100644 (file)
         <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_id128_get_invocation_app_specific</function></funcdef>
+        <paramdef>sd_id128_t <parameter>app_id</parameter></paramdef>
+        <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
+      </funcprototype>
+
     </funcsynopsis>
   </refsynopsisdiv>
 
     for details. The ID is cached internally. In future a different mechanism to determine the invocation ID
     may be added.</para>
 
+    <para><function>sd_id128_get_invocation_app_specific()</function> derives an application-specific ID from
+    the invocation ID.</para>
+
     <para>Note that <function>sd_id128_get_machine_app_specific()</function>,
-    <function>sd_id128_get_boot()</function>, <function>sd_id128_get_boot_app_specific()</function>, and
-    <function>sd_id128_get_invocation()</function> always return UUID Variant 1 Version 4 compatible IDs.
-    <function>sd_id128_get_machine()</function> will also return a UUID Variant 1 Version 4 compatible ID on
-    new installations but might not on older. It is possible to convert the machine ID non-reversibly into a
-    UUID Variant 1 Version 4 compatible one. For more information, see
+    <function>sd_id128_get_boot()</function>, <function>sd_id128_get_boot_app_specific()</function>,
+    <function>sd_id128_get_invocation()</function> and
+    <function>sd_id128_get_invocation_app_specific</function> always return UUID Variant 1 Version 4
+    compatible IDs. <function>sd_id128_get_machine()</function> will also return a UUID Variant 1 Version 4
+    compatible ID on new installations but might not on older. It is possible to convert the machine ID
+    non-reversibly into a UUID Variant 1 Version 4 compatible one. For more information, see
     <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>. It is
     hence guaranteed that these functions will never return the ID consisting of all zero or all one bits
     (<constant>SD_ID128_NULL</constant>, <constant>SD_ID128_ALLF</constant>) â€” with the possible exception of
@@ -262,6 +272,7 @@ As man:sd-id128(3) macro:
     <para><function>sd_id128_get_machine_app_specific()</function> was added in version 233.</para>
     <para><function>sd_id128_get_boot_app_specific()</function> was added in version 240.</para>
     <para><function>sd_id128_get_app_specific()</function> was added in version 255.</para>
+    <para><function>sd_id128_get_invocation_app_specific()</function> was added in version 256.</para>
   </refsect1>
 
   <refsect1>
index c8cf12a005993e67b2b1bff42a12aa02e50f27c5..0893b3f4e8216b5b5a9626f07d84608fbcc1d330 100644 (file)
 
     <table>
       <title>Partition Type GUIDs</title>
-      <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+      <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+        <colspec colname="type" />
         <colspec colname="guid" />
         <colspec colname="name" />
         <colspec colname="where" />
         <colspec colname="explanation" />
         <thead>
           <row>
-            <entry>Partition Type GUID</entry>
+            <entry>Partition Type</entry>
+            <entry>GUID</entry>
             <entry>Name</entry>
             <entry>Mount Point</entry>
             <entry>Explanation</entry>
         </thead>
         <tbody>
           <row>
-            <entry><constant>SD_GPT_ROOT_X86_64</constant> <constant>4f68bce3-e8cd-4db1-96e7-fbcaf984b709</constant></entry>
+            <entry><constant>SD_GPT_ROOT_X86_64</constant></entry>
+            <entry><constant>4f68bce3-e8cd-4db1-96e7-fbcaf984b709</constant></entry>
             <entry><filename>Root Partition (x86-64)</filename></entry>
             <entry><filename>/</filename></entry>
-            <entry>The first partition with this type UUID, located on the same disk as the ESP, is used as the root file system <filename>/</filename> on AMD64 / 64-bit x86 systems.</entry>
+            <entry>The first partition with this type UUID, located on the same disk as the ESP used for booting, is used as the root file system <filename>/</filename> on AMD64 / 64-bit x86 systems.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_ROOT_ARM64</constant> <constant>b921b045-1df0-41c3-af44-4c6f280d3fae</constant></entry>
+            <entry><constant>SD_GPT_ROOT_ARM64</constant></entry>
+            <entry><constant>b921b045-1df0-41c3-af44-4c6f280d3fae</constant></entry>
             <entry><filename>Root Partition (64-bit ARM)</filename></entry>
             <entry><filename>/</filename></entry>
-            <entry>The first partition with this type UUID, located on the same disk as the ESP, is used as the root file system <filename>/</filename> on AArch64 / 64-bit ARM systems.</entry>
+            <entry>The first partition with this type UUID, located on the same disk as the ESP used for booting, is used as the root file system <filename>/</filename> on AArch64 / 64-bit ARM systems.</entry>
           </row>
           <row>
-            <entry>
-              <constant>SD_GPT_ROOT_ALPHA</constant> <constant>SD_GPT_ROOT_ARC</constant> <constant>SD_GPT_ROOT_ARM</constant> <constant>SD_GPT_ROOT_ARM64</constant> <constant>SD_GPT_ROOT_IA64</constant> <constant>SD_GPT_ROOT_LOONGARCH64</constant> <constant>SD_GPT_ROOT_MIPS</constant> <constant>SD_GPT_ROOT_MIPS64</constant> <constant>SD_GPT_ROOT_MIPS_LE</constant> <constant>SD_GPT_ROOT_MIPS64_LE</constant> <constant>SD_GPT_ROOT_PARISC</constant> <constant>SD_GPT_ROOT_PPC</constant> <constant>SD_GPT_ROOT_PPC64</constant> <constant>SD_GPT_ROOT_PPC64_LE</constant> <constant>SD_GPT_ROOT_RISCV32</constant> <constant>SD_GPT_ROOT_RISCV64</constant> <constant>SD_GPT_ROOT_S390</constant> <constant>SD_GPT_ROOT_S390X</constant> <constant>SD_GPT_ROOT_TILEGX</constant> <constant>SD_GPT_ROOT_X86</constant> <constant>SD_GPT_ROOT_X86_64</constant> <constant>SD_GPT_USR_ALPHA</constant> <constant>SD_GPT_USR_ARC</constant> <constant>SD_GPT_USR_ARM</constant> <constant>SD_GPT_USR_IA64</constant> <constant>SD_GPT_USR_LOONGARCH64</constant> <constant>SD_GPT_USR_MIPS_LE</constant> <constant>SD_GPT_USR_MIPS64_LE</constant> <constant>SD_GPT_USR_PARISC</constant> <constant>SD_GPT_USR_PPC</constant> <constant>SD_GPT_USR_PPC64</constant> <constant>SD_GPT_USR_PPC64_LE</constant> <constant>SD_GPT_USR_RISCV32</constant> <constant>SD_GPT_USR_RISCV64</constant> <constant>SD_GPT_USR_S390</constant> <constant>SD_GPT_USR_S390X</constant> <constant>SD_GPT_USR_TILEGX</constant> <constant>SD_GPT_USR_X86</constant>
-            </entry>
-            <entry>root partitions for other architectures</entry>
+            <entry><constant>SD_GPT_ROOT_ALPHA</constant> <constant>SD_GPT_ROOT_ARC</constant> <constant>SD_GPT_ROOT_ARM</constant> <constant>SD_GPT_ROOT_ARM64</constant> <constant>SD_GPT_ROOT_IA64</constant> <constant>SD_GPT_ROOT_LOONGARCH64</constant> <constant>SD_GPT_ROOT_MIPS</constant> <constant>SD_GPT_ROOT_MIPS64</constant> <constant>SD_GPT_ROOT_MIPS_LE</constant> <constant>SD_GPT_ROOT_MIPS64_LE</constant> <constant>SD_GPT_ROOT_PARISC</constant> <constant>SD_GPT_ROOT_PPC</constant> <constant>SD_GPT_ROOT_PPC64</constant> <constant>SD_GPT_ROOT_PPC64_LE</constant> <constant>SD_GPT_ROOT_RISCV32</constant> <constant>SD_GPT_ROOT_RISCV64</constant> <constant>SD_GPT_ROOT_S390</constant> <constant>SD_GPT_ROOT_S390X</constant> <constant>SD_GPT_ROOT_TILEGX</constant> <constant>SD_GPT_ROOT_X86</constant> <constant>SD_GPT_ROOT_X86_64</constant> <constant>SD_GPT_USR_ALPHA</constant> <constant>SD_GPT_USR_ARC</constant> <constant>SD_GPT_USR_ARM</constant> <constant>SD_GPT_USR_IA64</constant> <constant>SD_GPT_USR_LOONGARCH64</constant> <constant>SD_GPT_USR_MIPS_LE</constant> <constant>SD_GPT_USR_MIPS64_LE</constant> <constant>SD_GPT_USR_PARISC</constant> <constant>SD_GPT_USR_PPC</constant> <constant>SD_GPT_USR_PPC64</constant> <constant>SD_GPT_USR_PPC64_LE</constant> <constant>SD_GPT_USR_RISCV32</constant> <constant>SD_GPT_USR_RISCV64</constant> <constant>SD_GPT_USR_S390</constant> <constant>SD_GPT_USR_S390X</constant> <constant>SD_GPT_USR_TILEGX</constant> <constant>SD_GPT_USR_X86</constant></entry>
+            <entry>…</entry>
+            <entry>Root partitions for other architectures</entry>
             <entry><filename>/</filename></entry>
-            <entry>The first partition with the type UUID matching the architecture, located on the same disk as the ESP, is used as the root file system <filename>/</filename>. For the full list and constant values, see <ulink url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">Discoverable Partitions Specification</ulink>.</entry>
+            <entry>The first partition with the type UUID matching the architecture, located on the same disk as the ESP used for booting, is used as the root file system <filename>/</filename>. For the full list and constant values, see <ulink url="https://uapi-group.org/specifications/specs/discoverable_partitions_specification">Discoverable Partitions Specification</ulink>.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_HOME</constant> <constant>933ac7e1-2eb4-4f13-b844-0e14e2aef915</constant></entry>
+            <entry><constant>SD_GPT_HOME</constant></entry>
+            <entry><constant>933ac7e1-2eb4-4f13-b844-0e14e2aef915</constant></entry>
             <entry>Home Partition</entry>
             <entry><filename>/home/</filename></entry>
-            <entry>The first partition with this type UUID on the same disk as the ESP is mounted to <filename>/home/</filename>.</entry>
+            <entry>The first partition with this type UUID on the same disk as the root partition is mounted to <filename>/home/</filename>.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_SRV</constant> <constant>3b8f8425-20e0-4f3b-907f-1a25a76f98e8</constant></entry>
+            <entry><constant>SD_GPT_SRV</constant></entry>
+            <entry><constant>3b8f8425-20e0-4f3b-907f-1a25a76f98e8</constant></entry>
             <entry>Server Data Partition</entry>
             <entry><filename>/srv/</filename></entry>
-            <entry>The first partition with this type UUID on the same disk as the ESP is mounted to <filename>/srv/</filename>.</entry>
+            <entry>The first partition with this type UUID on the same disk as the root partition is mounted to <filename>/srv/</filename>.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_VAR</constant> <constant>4d21b016-b534-45c2-a9fb-5c16e091fd2d</constant></entry>
+            <entry><constant>SD_GPT_VAR</constant></entry>
+            <entry><constant>4d21b016-b534-45c2-a9fb-5c16e091fd2d</constant></entry>
             <entry>Variable Data Partition</entry>
             <entry><filename>/var/</filename></entry>
-            <entry>The first partition with this type UUID on the same disk as the ESP is mounted to <filename>/var/</filename> â€” under the condition its partition UUID matches the first 128 bit of the HMAC-SHA256 of the GPT type uuid of this partition keyed by the machine ID of the installation stored in <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
+            <entry>The first partition with this type UUID on the same disk as the root partition is mounted to <filename>/var/</filename> â€” under the condition its partition UUID matches the first 128 bit of the HMAC-SHA256 of the GPT type uuid of this partition keyed by the machine ID of the installation stored in <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_TMP</constant> <constant>7ec6f557-3bc5-4aca-b293-16ef5df639d1</constant></entry>
+            <entry><constant>SD_GPT_TMP</constant></entry>
+            <entry><constant>7ec6f557-3bc5-4aca-b293-16ef5df639d1</constant></entry>
             <entry>Temporary Data Partition</entry>
             <entry><filename>/var/tmp/</filename></entry>
-            <entry>The first partition with this type UUID on the same disk as the ESP is mounted to <filename>/var/tmp/</filename>.</entry>
+            <entry>The first partition with this type UUID on the same disk as the root partition is mounted to <filename>/var/tmp/</filename>.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_SWAP</constant> <constant>0657fd6d-a4ab-43c4-84e5-0933c84b4f4f</constant></entry>
+            <entry><constant>SD_GPT_SWAP</constant></entry>
+            <entry><constant>0657fd6d-a4ab-43c4-84e5-0933c84b4f4f</constant></entry>
             <entry>Swap</entry>
             <entry>n/a</entry>
-            <entry>All partitions with this type UUID on the same disk as the ESP are used as swap.</entry>
+            <entry>All partitions with this type UUID on the same disk as the root partition are used as swap.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_ESP</constant> <constant>c12a7328-f81f-11d2-ba4b-00a0c93ec93b</constant></entry>
+            <entry><constant>SD_GPT_ESP</constant></entry>
+            <entry><constant>c12a7328-f81f-11d2-ba4b-00a0c93ec93b</constant></entry>
             <entry>EFI System Partition (ESP)</entry>
             <entry><filename>/efi/</filename> or <filename>/boot/</filename></entry>
             <entry>The first partition with this type UUID located on the same disk as the root partition is mounted to <filename>/boot/</filename> or <filename>/efi/</filename>, see below.</entry>
           </row>
           <row>
-            <entry><constant>SD_GPT_XBOOTLDR</constant> <constant>bc13c2ff-59e6-4262-a352-b275fd6f7172</constant></entry>
+            <entry><constant>SD_GPT_XBOOTLDR</constant></entry>
+            <entry><constant>bc13c2ff-59e6-4262-a352-b275fd6f7172</constant></entry>
             <entry>Extended Boot Loader Partition</entry>
             <entry><filename>/boot/</filename></entry>
             <entry>The first partition with this type UUID located on the same disk as the root partition is mounted to <filename>/boot/</filename>, see below.</entry>
 
     <table>
       <title>Partition Attribute Flags</title>
-      <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+      <tgroup cols='4' align='left' colsep='1' rowsep='1'>
         <colspec colname="flag" />
+        <colspec colname="value" />
         <colspec colname="where" />
         <colspec colname="explanation" />
         <thead>
           <row>
             <entry>Flag</entry>
+            <entry>Value</entry>
             <entry>Applicable to</entry>
             <entry>Explanation</entry>
           </row>
         </thead>
         <tbody>
           <row>
-            <entry><constant>SD_GPT_FLAG_READ_ONLY</constant> <constant>0x1000000000000000</constant></entry>
+            <entry><constant>SD_GPT_FLAG_READ_ONLY</constant></entry>
+            <entry><constant>0x1000000000000000</constant></entry>
             <entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>, <filename>/var/tmp/</filename>, Extended Boot Loader Partition</entry>
             <entry>Partition is mounted read-only</entry>
           </row>
 
           <row>
-            <entry><constant>SD_GPT_FLAG_NO_AUTO</constant> <constant>0x8000000000000000</constant></entry>
+            <entry><constant>SD_GPT_FLAG_NO_AUTO</constant></entry>
+            <entry><constant>0x8000000000000000</constant></entry>
             <entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, <filename>/var/</filename>, <filename>/var/tmp/</filename>, Extended Boot Loader Partition</entry>
             <entry>Partition is not mounted automatically</entry>
           </row>
 
           <row>
-            <entry><constant>SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL</constant> <constant>0x0000000000000002</constant></entry>
+            <entry><constant>SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL</constant></entry>
+            <entry><constant>0x0000000000000002</constant></entry>
             <entry>EFI System Partition (ESP)</entry>
             <entry>Partition is not mounted automatically</entry>
           </row>
index 1707e0c7f3b3449cf9862c880e056151cd2653bf..8ea667426edb8a982e5153a7d96319b405355661 100644 (file)
@@ -75,9 +75,9 @@
         <listitem><para>Pre-calculate the expected values seen in PCR register 11 after boot-up of a unified
         kernel image consisting of the components specified with <option>--linux=</option>,
         <option>--osrel=</option>, <option>--cmdline=</option>, <option>--initrd=</option>,
-        <option>--splash=</option>, <option>--dtb=</option>, <option>--uname=</option>,
-        <option>--sbat=</option>, <option>--pcrpkey=</option> see below. Only <option>--linux=</option> is
-        mandatory. (Alternatively, specify <option>--current</option> to use the current values of PCR
+        <option>--ucode=</option>, <option>--splash=</option>, <option>--dtb=</option>,
+        <option>--uname=</option>, <option>--sbat=</option>, <option>--pcrpkey=</option> see below.
+        Only <option>--linux=</option> is mandatory. (Alternatively, specify <option>--current</option> to use the current values of PCR
         register 11 instead.)</para>
 
         <xi:include href="version-info.xml" xpointer="v252"/>
         <term><option>--osrel=<replaceable>PATH</replaceable></option></term>
         <term><option>--cmdline=<replaceable>PATH</replaceable></option></term>
         <term><option>--initrd=<replaceable>PATH</replaceable></option></term>
+        <term><option>--ucode=<replaceable>PATH</replaceable></option></term>
         <term><option>--splash=<replaceable>PATH</replaceable></option></term>
         <term><option>--dtb=<replaceable>PATH</replaceable></option></term>
         <term><option>--uname=<replaceable>PATH</replaceable></option></term>
index 6a65ac33f85d59a027a39889bdcf09b30e5a4f10..e7e8a42a6d336bfae02ca99326e34c568fd27168 100644 (file)
@@ -70,6 +70,9 @@
 
       <listitem><para>An <literal>.initrd</literal> section with the initrd.</para></listitem>
 
+      <listitem><para>A <literal>.ucode</literal> section with an initrd containing microcode, to be handed
+      to the kernel before any other initrd. This initrd must not be compressed.</para></listitem>
+
       <listitem><para>A <literal>.splash</literal> section with an image (in the Windows
       <filename>.BMP</filename> format) to show on screen before invoking the kernel.</para></listitem>
 
     core kernel, the embedded initrd and kernel command line (see above for a full list).</para>
 
     <para>Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
-    every type of initrd will be measured two or three times: the initrd embedded in the kernel image will be
+    every type of initrd will be measured two or three times: the initrds embedded in the kernel image will be
     measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials (and the one synthesized
     from configuration extensions) will be measured to both PCR 9 and PCR 12; the initrd synthesized from
     system extensions will be measured to both PCR 4 and PCR 9. Let's summarize the OS resources and the PCRs
             <entry>4 + 9 + 11</entry>
           </row>
 
+          <row>
+            <entry>Microcode initrd (embedded in unified PE binary)</entry>
+            <entry>4 + 9 + 11</entry>
+          </row>
+
           <row>
             <entry>Default kernel command line (embedded in unified PE binary)</entry>
             <entry>4 + 11</entry>
index f9649b2f30a829ef1278308f0dbc0c2f9e56e6ab..8f196dd3525f720351c2c9918b0bc9bce94099ab 100644 (file)
@@ -1,6 +1,9 @@
 <?xml version='1.0'?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
 <!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
 
 <refentry id="systemd-vmspawn" conditional="ENABLE_VMSPAWN"
 
         <listitem><para>Directory to use as file system root for the virtual machine.</para>
 
-        <para>One of either <option>--directory=</option> or <option>--image=</option> must be specified.</para>
+        <para>One of either <option>--directory=</option> or <option>--image=</option> must be specified.
+        If neither are specified <option>--directory=.</option> is assumed.</para>
 
         <para>Note: If mounting a non-root owned directory you may require <option>--private-users=</option>
-              to map into the user's subuid namespace.</para>
+        to map into the user's subuid namespace. An example of how to use <constant>/etc/subuid</constant>
+        for this is given later.</para>
 
         <xi:include href="version-info.xml" xpointer="v256"/>
         </listitem>
         <varlistentry>
           <term><option>--cpus=<replaceable>CPUS</replaceable></option></term>
 
-          <listitem><para>Configures the number of CPUs to start the virtual machine with.
+          <listitem><para>The number of CPUs to start the virtual machine with.
           Defaults to 1.</para>
 
           <xi:include href="version-info.xml" xpointer="v255"/>
         <varlistentry>
           <term><option>--ram=<replaceable>BYTES</replaceable></option></term>
 
-          <listitem><para>Configures the amount of memory to start the virtual machine with.
+          <listitem><para>The amount of memory to start the virtual machine with.
           Defaults to 2G.</para>
 
           <xi:include href="version-info.xml" xpointer="v255"/>
         <varlistentry>
           <term><option>--kvm=<replaceable>BOOL</replaceable></option></term>
 
-          <listitem><para>Configures whether to use KVM. If the option is not specified KVM support will be
+          <listitem><para>If <option>--kvm=</option> is not specified KVM support will be
           detected automatically. If true, KVM is always used, and if false, KVM is never used.</para>
 
           <xi:include href="version-info.xml" xpointer="v255"/></listitem>
         <varlistentry>
           <term><option>--vsock=<replaceable>BOOL</replaceable></option></term>
 
-          <listitem>
-            <para>Configure whether to use VSOCK networking.</para>
+          <listitem><para>If <option>--vsock=</option> is not specified VSOCK networking support will be
+          detected automatically. If true, VSOCK networking is always used, and if false, VSOCK networking is never used.</para>
 
-            <para>If the option is not specified VSOCK support will be detected automatically.  If yes is
-            specified VSOCK is always used, and vice versa if no is set VSOCK are never used.</para>
-            <xi:include href="version-info.xml" xpointer="v255"/>
-          </listitem>
+          <xi:include href="version-info.xml" xpointer="v255"/></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><option>--vsock-cid=<replaceable>CID</replaceable></option></term>
 
           <listitem>
-            <para>Configure vmspawn to use a specific CID for the guest.</para>
-
-            <para>If the option is not specified or an empty argument is supplied the guest will be assigned a random CID.</para>
-
-            <para>Valid CIDs are in the range <constant>3</constant> to <constant>4294967294</constant> (<constant>0xFFFF_FFFE</constant>).
-            CIDs outside of this range are reserved.</para>
+            <para>Sets the specific CID to use for the guest.
+            Valid CIDs are in the range <constant>3</constant> to <constant>4294967294</constant> (<constant>0xFFFF_FFFE</constant>).
+            CIDs outside of this range are reserved. By default vmspawn will attempt to derive a CID for the guest derived from the machine name,
+            falling back to a random CID if this CID is taken.</para>
 
             <xi:include href="version-info.xml" xpointer="v255"/>
           </listitem>
           <term><option>--tpm=<replaceable>BOOL</replaceable></option></term>
 
           <listitem>
-            <para>Configure whether to use VM with a virtual TPM or not.</para>
-
-            <para>If the option is not specified vmspawn will detect the presence of <citerefentry project='debian'>
+            <para>If <option>--tpm=</option> is not specified vmspawn will detect the presence of <citerefentry project='debian'>
             <refentrytitle>swtpm</refentrytitle><manvolnum>8</manvolnum></citerefentry> and use it if available.
             If yes is specified <citerefentry project='debian'><refentrytitle>swtpm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-            is always used, and vice versa if no is set <citerefentry project='debian'><refentrytitle>swtpm</refentrytitle>
+            is always used, and if no is set <citerefentry project='debian'><refentrytitle>swtpm</refentrytitle>
             <manvolnum>8</manvolnum></citerefentry> is never used.</para>
 
             <para>Note: the virtual TPM used may change in future.</para>
           <term><option>--linux=<replaceable>PATH</replaceable></option></term>
 
           <listitem>
-            <para>Set the linux kernel image to use for direct kernel boot.</para>
-
-            <para>If no kernel was installed into the image then the image will fail to boot.</para>
+            <para>Set the linux kernel image to use for direct kernel boot.
+            If a directory type image is used and <option>--linux=</option> was omitted, vmspawn will search for boot loader entries
+            according to the
+            <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink> assuming
+            XBOOTLDR to be located at /boot and ESP to be /efi respectively.
+            If no kernel was installed into the image then the image will fail to boot.</para>
 
             <xi:include href="version-info.xml" xpointer="v256"/>
           </listitem>
           <term><option>--initrd=<replaceable>PATH</replaceable></option></term>
 
           <listitem>
-            <para>Set the initrd to use for direct kernel boot.</para>
+            <para>Set the initrd to use for direct kernel boot.
+            If the <option>--linux=</option> supplied is a
+            <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>
+            Type #2 entry, then this argument is not required.
+            If no initrd was installed into the image then the image will fail to boot.</para>
 
-            <para>If the linux kernel supplied is a UKI then this argument is not required.</para>
-
-            <para>If the option is specified multiple times vmspawn will merge the initrds together.</para>
-
-            <para>If no initrd was installed into the image then the image will fail to boot.</para>
+            <para><option>--initrd=</option> can be specified multiple times and vmspawn will merge them together.</para>
 
             <xi:include href="version-info.xml" xpointer="v256"/>
           </listitem>
           <term><option>--private-users=<replaceable>UID_SHIFT[:UID_RANGE]</replaceable></option></term>
 
           <listitem><para>Controls user namespacing under <option>--directory=</option>.
-          If enabled, <command>virtiofsd</command> is instructed to map user and group ids (UIDs and GIDs).
+          If enabled,
+          <citerefentry><refentrytitle>virtiofsd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+          is instructed to map user and group ids (UIDs and GIDs).
           This involves mapping the private UIDs/GIDs used in the virtual machine (starting with the virtual machine's
           root user 0 and up) to a range of UIDs/GIDs on the host that are not used for other purposes (usually in the
           range beyond the host's UID/GID 65536).</para>
           for more information.</para>
 
           <para>By default <literal>ed25519</literal> keys are generated, however <literal>rsa</literal> keys
-          may also be useful if the VM has a particularly old version of <command>sshd</command></para>.
+          may also be useful if the VM has a particularly old version of <command>sshd</command>.</para>
 
           <xi:include href="version-info.xml" xpointer="v256"/>
           </listitem>
@@ -507,6 +510,53 @@ $ mkosi -d arch -p systemd -p linux --autologin -o image.raw -f build
 $ systemd-vmspawn --image=image.raw
       </programlisting>
     </example>
+
+    <example>
+      <title>Import and run a Fedora 39 Cloud image using machinectl</title>
+
+      <programlisting>
+$ curl -L \
+       -O https://download.fedoraproject.org/pub/fedora/linux/releases/&fedora_latest_version;/Cloud/x86_64/images/Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86_64.raw.xz \
+       -O https://download.fedoraproject.org/pub/fedora/linux/releases/&fedora_latest_version;/Cloud/x86_64/images/Fedora-Cloud-&fedora_latest_version;-&fedora_cloud_release;-x86_64-CHECKSUM \
+       -O https://fedoraproject.org/fedora.gpg
+$ gpgv --keyring ./fedora.gpg Fedora-Cloud-&fedora_latest_version;-&fedora_cloud_release;-x86_64-CHECKSUM
+$ sha256sum -c Fedora-Cloud-&fedora_latest_version;-&fedora_cloud_release;-x86_64-CHECKSUM
+# machinectl import-raw Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86_64.raw.xz fedora-&fedora_latest_version;-cloud
+# systemd-vmspawn -M fedora-&fedora_latest_version;-cloud
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Build and run systemd's system image and forward the VM's journal to a local file</title>
+
+      <programlisting>
+$ mkosi build
+$ systemd-vmspawn \
+    -D mkosi.output/system \
+    --private-users $(grep $(whoami) /etc/subuid | cut -d: -f2) \
+    --linux mkosi.output/system.efi \
+    --forward-journal=vm.journal \
+    enforcing=0
+      </programlisting>
+
+      <para>Note: this example also uses a kernel command line argument to ensure SELinux isn't started in enforcing mode.</para>
+    </example>
+
+    <example>
+      <title>SSH into a running VM using <command>systemd-ssh-proxy</command></title>
+
+      <programlisting>
+$ mkosi build
+$ my_vsock_cid=3735928559
+$ systemd-vmspawn \
+    -D mkosi.output/system \
+    --private-users $(grep $(whoami) /etc/subuid | cut -d: -f2) \
+    --linux mkosi.output/system.efi \
+    --vsock-cid $my_vsock_cid \
+    enforcing=0
+$ ssh root@vsock/$my_vsock_cid -i /run/user/$UID/systemd/vmspawn/machine-*-system-ed25519
+      </programlisting>
+    </example>
   </refsect1>
 
   <refsect1>
@@ -524,6 +574,7 @@ $ systemd-vmspawn --image=image.raw
       <member><citerefentry project='debian'><refentrytitle>mkosi</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
       <member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+      <member><ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink></member>
     </simplelist></para>
   </refsect1>
 </refentry>
index 5e8361f69af1be42d8157b63841db2ef173d1170..916eb5bffe7233fc55c0352615facb73e6c28ee6 100644 (file)
@@ -747,6 +747,17 @@ Table=1234</programlisting></para>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>UseDomains=</varname></term>
+        <listitem>
+          <para>Specifies the protocol-independent default value for the same settins in
+          [IPv6AcceptRA], [DHCPv4], and [DHCPv6] sections below. Takes a boolean, or the special value
+          <option>route</option>. See also the same setting in [DHCPv4] below. Defaults to unset.</para>
+
+          <xi:include href="version-info.xml" xpointer="v256"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>Domains=</varname></term>
         <listitem>
@@ -2571,9 +2582,15 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting>
           effect of the <option>Domains=</option> setting. If set to <option>route</option>, the domain name
           received from the DHCP server will be used for routing DNS queries only, but not for searching,
           similarly to the effect of the <option>Domains=</option> setting when the argument is prefixed with
-          <literal>~</literal>. When unspecified, the value specified in the same setting in
-          <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-          which defaults to <literal>no</literal>, will be used.</para>
+          <literal>~</literal>.</para>
+
+          <para>When unspecified, the value specified in the same setting in the [Network] section will be
+          used. When it is unspecified, the value specified in the same setting in the [DHCPv4] section in
+          <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+          will be used. When it is unspecified, the value specified in the same setting in the [Network]
+          section in
+          <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+          will be used. When none of them are specified, defaults to <literal>no</literal>.</para>
 
           <para>It is recommended to enable this option only on trusted networks, as setting this
           affects resolution of all hostnames, in particular of single-label names. It is generally
index a81cbcb47b5df358bb1b0b2e8eb41fe7ac445c7d..a9034bc51114a5581fbb3102327a18522ff26bea 100644 (file)
@@ -67,6 +67,7 @@
 
       <para>Additional sections will be inserted into the UKI, either automatically or only if a specific
       option is provided. See the discussions of
+      <varname>Microcode=</varname>/<option>--microcode=</option>,
       <varname>Cmdline=</varname>/<option>--cmdline=</option>,
       <varname>OSRelease=</varname>/<option>--os-release=</option>,
       <varname>DeviceTree=</varname>/<option>--devicetree=</option>,
           <xi:include href="version-info.xml" xpointer="v254"/></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>Microcode=<replaceable>UCODE</replaceable></varname></term>
+          <term><option>--microcode=<replaceable>UCODE</replaceable></option></term>
+
+          <listitem><para>Path to initrd containing microcode updates. If not specified, the section
+          will not be present.</para>
+
+          <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>Cmdline=<replaceable>TEXT</replaceable>|<replaceable>@PATH</replaceable></varname></term>
           <term><option>--cmdline=<replaceable>TEXT</replaceable>|<replaceable>@PATH</replaceable></option></term>
index b9c928b027b8d22c2c5995febf02ef0f2d32ebc7..02f6a90b6f3010af903f18d3f1d6b168f8acc7df 100644 (file)
@@ -17,29 +17,30 @@ Environment=ASAN_OPTIONS=verify_asan_link_order=false
 @SELinuxRelabel=no
 BuildSourcesEphemeral=yes
 
+KernelCommandLine=systemd.crash_shell
+                  systemd.log_level=debug,console:info
+                  systemd.log_ratelimit_kmsg=0
+                  systemd.journald.forward_to_console
+                  systemd.journald.max_level_console=warning
+                  # Disable the kernel's ratelimiting on userspace logging to kmsg.
+                  printk.devkmsg=on
+                  # Make sure /sysroot is mounted rw in the initrd.
+                  rw
+                  # Lower the default device timeout so we get a shell earlier if the root device does
+                  # not appear for some reason.
+                  systemd.default_device_timeout_sec=20
+                  # Make sure no LSMs are enabled by default.
+                  apparmor=0
+                  selinux=0
+                  enforcing=0
+                  systemd.early_core_pattern=/core
+                  systemd.firstboot=no
+                  systemd.setenv=SYSTEMD_ENABLE_LOG_CONTEXT=yes
+                  SYSTEMD_ENABLE_LOG_CONTEXT=yes
+
 [Host]
 @Incremental=yes
 @RuntimeSize=8G
 @RuntimeBuildSources=yes
 @QemuSmp=2
 ToolsTreePackages=virtiofsd
-KernelCommandLineExtra=systemd.crash_shell
-                       systemd.log_level=debug,console:info
-                       systemd.log_ratelimit_kmsg=0
-                       systemd.journald.forward_to_console
-                       systemd.journald.max_level_console=warning
-                       # Disable the kernel's ratelimiting on userspace logging to kmsg.
-                       printk.devkmsg=on
-                       # Make sure /sysroot is mounted rw in the initrd.
-                       rw
-                       # Lower the default device timeout so we get a shell earlier if the root device does
-                       # not appear for some reason.
-                       systemd.default_device_timeout_sec=20
-                       # Make sure no LSMs are enabled by default.
-                       apparmor=0
-                       selinux=0
-                       enforcing=0
-                       systemd.early_core_pattern=/core
-                       systemd.firstboot=no
-                       systemd.setenv=SYSTEMD_ENABLE_LOG_CONTEXT=yes
-                       SYSTEMD_ENABLE_LOG_CONTEXT=yes
index 92d58292f4c7919a390484f720652de1d23825fd..cf5d4f3103f05aa7b1337e71b4090e95a8397dda 100644 (file)
@@ -6,10 +6,11 @@ Distribution=arch
 [Content]
 VolatilePackages=
         systemd
-        systemd-ukify
-        systemd-sysvcompat
+        systemd-libs
         systemd-resolvconf
+        systemd-sysvcompat
         systemd-tests
+        systemd-ukify
 
 Packages=
         bpf
@@ -25,6 +26,7 @@ Packages=
         git
         gnutls
         iproute
+        iputils
         linux
         man-db
         openbsd-netcat
@@ -33,6 +35,7 @@ Packages=
         pacman
         pkgconf
         polkit
+        procps-ng
         quota-tools
         sbsigntools
         shadow
@@ -45,4 +48,5 @@ InitrdPackages=
 
 InitrdVolatilePackages=
         systemd
+        systemd-libs
         systemd-sysvcompat
index f745a2c002efd09c537031460835d2fcb5a3aba5..8c4c2469aee06783b8e39b92701bc87f4491bad8 100755 (executable)
@@ -32,16 +32,16 @@ ARCH="$(rpm --eval %_arch)"
 SRCDEST="/usr/src/debug/systemd-$VERSION-${RELEASE}${DIST}.$ARCH"
 
 # TODO: Drop -U_FORTIFY_SOURCE when we switch to CentOS Stream 10.
-EXTRA_CFLAGS="-O0 -Wp,-U_FORTIFY_SOURCE"
+CFLAGS="$(rpm --define "_fortify_level 0" --undefine _lto_cflags --eval %build_cflags) -O0 -Wp,-U_FORTIFY_SOURCE"
 if ((WITH_DEBUG)); then
-    EXTRA_CFLAGS="$EXTRA_CFLAGS -ffile-prefix-map=../src=$SRCDEST"
+    CFLAGS="$CFLAGS -ffile-prefix-map=../src=$SRCDEST"
 fi
 
 IFS=
 # TODO: Replace meson_build and meson_install overrides with "--undefine __meson_verbose" once
 # https://github.com/mesonbuild/meson/pull/12835 is available.
 # shellcheck disable=SC2046
-rpmbuild \
+ANNOBIN="no-active-checks" rpmbuild \
     -bb \
     --build-in-place \
     --with upstream \
@@ -58,7 +58,7 @@ rpmbuild \
     $( ((WITH_DEBUG)) || echo "debug_package %{nil}") \
     --define "version_override $VERSION" \
     --define "release_override $RELEASE" \
-    --define "build_cflags $(rpm --eval %build_cflags) $EXTRA_CFLAGS" \
+    --define "build_cflags $CFLAGS" \
     --define "meson_build %{shrink:%{__meson} compile -C %{_vpath_builddir} -j %{_smp_build_ncpus} %{nil}}" \
     --define "meson_install %{shrink:DESTDIR=%{buildroot} %{__meson} install -C %{_vpath_builddir} --no-rebuild --quiet %{nil}}" \
     --define "meson_extra_configure_options -D mode=developer -D b_sanitize=${SANITIZERS:-none}" \
@@ -74,6 +74,7 @@ rpmbuild \
     --define "_find_debuginfo_dwz_opts %{nil}" \
     --define "_fortify_level 0" \
     --undefine _lto_cflags \
+    --undefine _package_note_flags \
     --noclean \
     "pkg/$ID/systemd.spec"
 
index 4344b51fa0312169f4695db54e04354fd27dc8e8..294e4cdf2897d4933ce0b60302f2c8a3735edeb5 100644 (file)
@@ -30,6 +30,7 @@ Packages=
         integritysetup
         iproute
         iproute-tc
+        iputils
         kernel-core
         libasan
         libcap-ng-utils
@@ -41,6 +42,7 @@ Packages=
         p11-kit
         pam
         passwd
+        policycoreutils
         polkit
         procps-ng
         quota
@@ -50,7 +52,6 @@ Packages=
         selinux-policy
         selinux-policy-targeted
         setools-console
-        policycoreutils
         util-linux
         vim-common
 
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-groups.conf b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-groups.conf
new file mode 100644 (file)
index 0000000..d69ff91
--- /dev/null
@@ -0,0 +1,24 @@
+g root 0
+g bin 1
+g daemon 2
+g sys 3
+g adm 4
+g tty 5
+g disk 6
+g lp 7
+g mem 8
+g kmem 9
+g wheel 10
+g cdrom 11
+g mail 12
+g man 15
+g dialout 18
+g floppy 19
+g games 20
+g tape 33
+g video 39
+g ftp 50
+g lock 54
+g audio 63
+g users 100
+g nobody 65534
diff --git a/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-users.conf b/mkosi.images/system/mkosi.conf.d/10-centos/mkosi.extra/usr/lib/sysusers.d/20-setup-users.conf
new file mode 100644 (file)
index 0000000..bea0ab3
--- /dev/null
@@ -0,0 +1,13 @@
+u root 0:0 "Super User" /root /bin/bash
+u bin 1:1 "bin" /bin -
+u daemon 2:2 "daemon" /sbin -
+u adm 3:4 "adm" /var/adm -
+u lp 4:7 "lp" /var/spool/lpd -
+u sync 5:0 "sync" /sbin /bin/sync
+u shutdown 6:0 "shutdown" /sbin /sbin/shutdown
+u halt 7:0 "halt" /sbin /sbin/halt
+u mail 8:12 "mail" /var/spool/mail -
+u operator 11:0 "operator" /root -
+u games 12:100 "games" /usr/games -
+u ftp 14:50 "FTP User" /var/ftp -
+u nobody 65534:65534 "Kernel Overflow User" - -
index 7144d73f104a810ce726e7578be96e9b6ada5cb8..ce80e5513f649907e2791561282d64c8e4f371b2 100644 (file)
@@ -46,6 +46,7 @@ Packages=
         fdisk
         git-core
         iproute2
+        iputils-ping
         isc-dhcp-server
         libcap-ng-utils
         libtss2-rc0
index dbc6f945af810e436bc422e8c30122bbad7a5b9e..5bcf7b8efd557bf055d7bba90db9ca1a8ed7213d 100644 (file)
@@ -36,7 +36,13 @@ Packages=
         git-core
         glibc-locale-base
         grep
+        group(bin)
+        group(daemon)
+        group(games)
+        group(nobody)
+        group(root)
         gzip
+        iputils
         kernel-kvmsmall
         kmod
         libasan8
@@ -46,6 +52,7 @@ Packages=
         openssh-server
         pam
         patterns-base-minimal_base
+        procps4
         python3-pefile
         quota
         rpm-build
@@ -54,6 +61,11 @@ Packages=
         sed
         shadow
         timezone
+        user(bin)
+        user(daemon)
+        user(games)
+        user(nobody)
+        user(root)
         vim
         xz
 
index d1052694aa711012d58f703c8fb16f3904300d4b..8a00ca9f6884106e2d7d8901fa607863e876c6e1 100755 (executable)
@@ -2,6 +2,10 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 set -e
 
+# Make sure serial console line wrapping is re-enabled as qemu's seabios firmware disables serial console
+# line-wrapping on boot.
+echo "tput smam || :" >>/etc/profile
+
 if [ -n "$SANITIZERS" ]; then
     LD_PRELOAD=$(ldd /usr/lib/systemd/systemd | grep libasan.so | awk '{print $3}')
 
index d941484d986ed963eb717dc7455bb2c567574781..9a904d3947a634465ea297f0b3c5f29318e569b9 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -6,16 +6,16 @@ msgid ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2024-03-04 10:09+0100\n"
-"PO-Revision-Date: 2024-01-21 10:36+0000\n"
+"PO-Revision-Date: 2024-04-20 07:36+0000\n"
 "Last-Translator: Andika Triwidada <andika@gmail.com>\n"
 "Language-Team: Indonesian <https://translate.fedoraproject.org/projects/"
-"systemd/master/id/>\n"
+"systemd/main/id/>\n"
 "Language: id\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 5.3.1\n"
+"X-Generator: Weblate 5.4\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -132,23 +132,22 @@ msgstr ""
 
 #: src/home/org.freedesktop.home1.policy:73
 msgid "Inhibit automatic lock of a home area"
-msgstr ""
+msgstr "Cegah penguncian otomatis dari area home"
 
 #: src/home/org.freedesktop.home1.policy:74
-#, fuzzy
 msgid ""
 "Authentication is required to inhibit automatic lock of a user's home area."
-msgstr "Otentikasi diperlukan untuk memperbarui suatu area rumah pengguna."
+msgstr ""
+"Otentikasi diperlukan untuk mencegah penguncian otomatis dari area home "
+"pengguna."
 
 #: src/home/org.freedesktop.home1.policy:83
-#, fuzzy
 msgid "Activate a home area"
-msgstr "Menciptakan suatu area rumah"
+msgstr "Aktifkan suatu area home"
 
 #: src/home/org.freedesktop.home1.policy:84
-#, fuzzy
 msgid "Authentication is required to activate a user's home area."
-msgstr "Otentikasi diperlukan untuk mencipta suatu area rumah pengguna."
+msgstr "Otentikasi diperlukan untuk mengaktifkan suatu area home pengguna."
 
 #: src/home/pam_systemd_home.c:293
 #, c-format
@@ -370,46 +369,39 @@ msgid "Authentication is required to get system description."
 msgstr "Otentikasi diperlukan untuk mendapatkan deskripsi sistem."
 
 #: src/import/org.freedesktop.import1.policy:22
-#, fuzzy
 msgid "Import a disk image"
-msgstr "Impor sebuah image kontainer atau VM"
+msgstr "Impor sebuah image disk"
 
 #: src/import/org.freedesktop.import1.policy:23
-#, fuzzy
 msgid "Authentication is required to import an image"
-msgstr "Otentikasi diperlukan untuk mengimpor suatu image kontainer atau VM"
+msgstr "Otentikasi diperlukan untuk mengimpor suatu image"
 
 #: src/import/org.freedesktop.import1.policy:32
-#, fuzzy
 msgid "Export a disk image"
-msgstr "Ekspor sebuah image kontainer atau VM"
+msgstr "Ekspor sebuah image disk"
 
 #: src/import/org.freedesktop.import1.policy:33
-#, fuzzy
 msgid "Authentication is required to export disk image"
-msgstr "Otentikasi diperlukan untuk mengekspor suatu image kontainer atau VM"
+msgstr "Otentikasi diperlukan untuk mengekspor suatu image disk"
 
 #: src/import/org.freedesktop.import1.policy:42
-#, fuzzy
 msgid "Download a disk image"
-msgstr "Unduh sebuah image kontainer atau VM"
+msgstr "Unduh sebuah image disk"
 
 #: src/import/org.freedesktop.import1.policy:43
-#, fuzzy
 msgid "Authentication is required to download a disk image"
-msgstr "Otentikasi diperlukan untuk mengunduh suatu image kontainer atau VM"
+msgstr "Otentikasi diperlukan untuk mengunduh suatu image disk"
 
 #: src/import/org.freedesktop.import1.policy:52
 msgid "Cancel transfer of a disk image"
-msgstr ""
+msgstr "Batalkan transfer suatu image disk"
 
 #: src/import/org.freedesktop.import1.policy:53
-#, fuzzy
 msgid ""
 "Authentication is required to cancel the ongoing transfer of a disk image"
 msgstr ""
-"Otentikasi diperlukan untuk mengubah kata sandi dari suatu area rumah "
-"pengguna."
+"Otentikasi diperlukan untuk membatalkan transfer suatu image disk yang "
+"sedang berjalan"
 
 #: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
index 6faa6ad4fcef8de0e3f28211a388ded74f594d46..0d740c675ecf8e8d48961659dca71bdc90c11c15 100644 (file)
@@ -256,7 +256,7 @@ fail:
         return r;
 }
 
-static bool stderr_is_journal(void) {
+bool stderr_is_journal(void) {
         _cleanup_free_ char *w = NULL;
         const char *e;
         uint64_t dev, ino;
index 6df164e06f785a9db0890aedd06b18f8e7997812..726f035cfca3ec09fe70573038568ee52a0cf5ac 100644 (file)
@@ -85,6 +85,7 @@ int log_show_tid_from_string(const char *e);
 assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
 #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1])
 
+bool stderr_is_journal(void);
 int log_open(void);
 void log_close(void);
 void log_forget_fds(void);
index 7e2c0781fe12870bcd9e4bc36488c90ce5930c13..09703506f93367125bcd8a0c98952f7d0033056a 100644 (file)
@@ -447,7 +447,7 @@ static Virtualization detect_vm_zvm(void) {
 /* Returns a short identifier for the various VM implementations */
 Virtualization detect_vm(void) {
         static thread_local Virtualization cached_found = _VIRTUALIZATION_INVALID;
-        bool other = false;
+        bool other = false, hyperv = false;
         int xen_dom0 = 0;
         Virtualization v, dmi;
 
@@ -504,7 +504,12 @@ Virtualization detect_vm(void) {
         v = detect_vm_cpuid();
         if (v < 0)
                 return v;
-        if (v == VIRTUALIZATION_VM_OTHER)
+        if (v == VIRTUALIZATION_MICROSOFT)
+                /* QEMU sets the CPUID string to hyperv's, in case it provides hyperv enlightenments. Let's
+                 * hence not return Microsoft here but just use the other mechanisms first to make a better
+                 * decision. */
+                hyperv = true;
+        else if (v == VIRTUALIZATION_VM_OTHER)
                 other = true;
         else if (v != VIRTUALIZATION_NONE)
                 goto finish;
@@ -545,8 +550,15 @@ Virtualization detect_vm(void) {
                 return v;
 
 finish:
-        if (v == VIRTUALIZATION_NONE && other)
-                v = VIRTUALIZATION_VM_OTHER;
+        /* None of the checks above gave us a clear answer, hence let's now use fallback logic: if hyperv
+         * enlightenments are available but the VMM wasn't recognized as anything yet, it's probably
+         * Microsoft. */
+        if (v == VIRTUALIZATION_NONE) {
+                if (hyperv)
+                        v = VIRTUALIZATION_MICROSOFT;
+                else if (other)
+                        v = VIRTUALIZATION_VM_OTHER;
+        }
 
         cached_found = v;
         log_debug("Found VM virtualization %s", virtualization_to_string(v));
index 1408d74bb60b0bb03be0c8b30294bc9addf648ea..bd1118a58a5a3f2e85cfc97100844601d9805214 100644 (file)
@@ -65,7 +65,7 @@ static EFI_STATUS pack_cpio_one(
         char *a;
 
         assert(fname);
-        assert(contents_size || contents_size == 0);
+        assert(contents || contents_size == 0);
         assert(target_dir_prefix);
         assert(inode_counter);
         assert(cpio_buffer);
index 58586f942faa4ccb6bee87450be72e260944af76..9aa605b7563e06c7b4db37bbaf73782b075fa399 100644 (file)
@@ -26,28 +26,27 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION
 
 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
 
-static EFI_STATUS combine_initrd(
-                EFI_PHYSICAL_ADDRESS initrd_base, size_t initrd_size,
-                const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds,
+/* Combine initrds by concatenation in memory */
+static EFI_STATUS combine_initrds(
+                const void * const initrds[], const size_t initrd_sizes[], size_t n_initrds,
                 Pages *ret_initr_pages, size_t *ret_initrd_size) {
 
-        size_t n;
+        size_t n = 0;
 
         assert(ret_initr_pages);
         assert(ret_initrd_size);
 
-        /* Combines four initrds into one, by simple concatenation in memory */
-
-        n = ALIGN4(initrd_size); /* main initrd might not be padded yet */
-
-        for (size_t i = 0; i < n_extra_initrds; i++) {
-                if (!extra_initrds[i])
+        for (size_t i = 0; i < n_initrds; i++) {
+                if (!initrds[i])
                         continue;
 
-                if (n > SIZE_MAX - extra_initrd_sizes[i])
+                /* some initrds (the ones from UKI sections) need padding,
+                 * pad all to be safe */
+                size_t initrd_size = ALIGN4(initrd_sizes[i]);
+                if (n > SIZE_MAX - initrd_size)
                         return EFI_OUT_OF_RESOURCES;
 
-                n += extra_initrd_sizes[i];
+                n += initrd_size;
         }
 
         _cleanup_pages_ Pages pages = xmalloc_pages(
@@ -56,27 +55,21 @@ static EFI_STATUS combine_initrd(
                         EFI_SIZE_TO_PAGES(n),
                         UINT32_MAX /* Below 4G boundary. */);
         uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
-        if (initrd_base != 0) {
+        for (size_t i = 0; i < n_initrds; i++) {
+                if (!initrds[i])
+                        continue;
+
                 size_t pad;
 
-                /* Order matters, the real initrd must come first, since it might include microcode updates
-                 * which the kernel only looks for in the first cpio archive */
-                p = mempcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
+                p = mempcpy(p, initrds[i], initrd_sizes[i]);
 
-                pad = ALIGN4(initrd_size) - initrd_size;
+                pad = ALIGN4(initrd_sizes[i]) - initrd_sizes[i];
                 if (pad > 0)  {
                         memzero(p, pad);
                         p += pad;
                 }
         }
 
-        for (size_t i = 0; i < n_extra_initrds; i++) {
-                if (!extra_initrds[i])
-                        continue;
-
-                p = mempcpy(p, extra_initrds[i], extra_initrd_sizes[i]);
-        }
-
         assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
 
         *ret_initr_pages = pages;
@@ -503,8 +496,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
         void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL;
         char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL;
         _cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL;
-        size_t linux_size, initrd_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
-        EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
+        size_t linux_size, initrd_size, ucode_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
+        EFI_PHYSICAL_ADDRESS linux_base, initrd_base, ucode_base, dt_base;
         _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
         EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
         size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
@@ -541,6 +534,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
         CLEANUP_ARRAY(dt_filenames_addons_global, n_dts_addons_global, dt_filenames_free);
         CLEANUP_ARRAY(dt_filenames_addons_uki, n_dts_addons_uki, dt_filenames_free);
 
+        if (szs[UNIFIED_SECTION_UNAME] > 0)
+                uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
+                                  szs[UNIFIED_SECTION_UNAME]);
+
         /* Now that we have the UKI sections loaded, also load global first and then local (per-UKI)
          * addons. The data is loaded at once, and then used later. */
         err = load_addons(
@@ -615,10 +612,6 @@ static EFI_STATUS run(EFI_HANDLE image) {
         /* Show splash screen as early as possible */
         graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
 
-        if (szs[UNIFIED_SECTION_UNAME] > 0)
-                uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
-                                  szs[UNIFIED_SECTION_UNAME]);
-
         if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
                 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
                  * duplicates what we already did in the boot menu, if that was already used. However, since
@@ -792,12 +785,18 @@ static EFI_STATUS run(EFI_HANDLE image) {
         initrd_size = szs[UNIFIED_SECTION_INITRD];
         initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
 
+        ucode_size = szs[UNIFIED_SECTION_UCODE];
+        ucode_base = ucode_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_UCODE] : 0;
+
         _cleanup_pages_ Pages initrd_pages = {};
-        if (credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
-                /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
-                err = combine_initrd(
-                                initrd_base, initrd_size,
+        if (ucode_base || credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
+                /* If we have generated initrds dynamically or there is a microcode initrd, combine them with the built-in initrd. */
+                err = combine_initrds(
                                 (const void*const[]) {
+                                        /* Microcode must always be first as kernel only scans uncompressed cpios
+                                         * and later initrds might be compressed. */
+                                        PHYSICAL_ADDRESS_TO_POINTER(ucode_base),
+                                        PHYSICAL_ADDRESS_TO_POINTER(initrd_base),
                                         credential_initrd,
                                         global_credential_initrd,
                                         sysext_initrd,
@@ -806,6 +805,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
                                         pcrpkey_initrd,
                                 },
                                 (const size_t[]) {
+                                        ucode_size,
+                                        initrd_size,
                                         credential_initrd_size,
                                         global_credential_initrd_size,
                                         sysext_initrd_size,
@@ -813,7 +814,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
                                         pcrsig_initrd_size,
                                         pcrpkey_initrd_size,
                                 },
-                                6,
+                                8,
                                 &initrd_pages, &initrd_size);
                 if (err != EFI_SUCCESS)
                         return err;
index 789a3deb8ce276aee21cdb3c9fa65c2de45e9fc5..41fcd5a91ad1eafc39893afd9b5d059034609cd1 100644 (file)
@@ -92,6 +92,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --osrel=PATH        Path to os-release file                %7$s .osrel\n"
                "     --cmdline=PATH      Path to file with kernel command line  %7$s .cmdline\n"
                "     --initrd=PATH       Path to initrd image file              %7$s .initrd\n"
+               "     --ucode=PATH        Path to microcode image file           %7$s .ucode\n"
                "     --splash=PATH       Path to splash bitmap file             %7$s .splash\n"
                "     --dtb=PATH          Path to Devicetree file                %7$s .dtb\n"
                "     --uname=PATH        Path to 'uname -r' file                %7$s .uname\n"
@@ -133,6 +134,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_OSREL,
                 ARG_CMDLINE,
                 ARG_INITRD,
+                ARG_UCODE,
                 ARG_SPLASH,
                 ARG_DTB,
                 ARG_UNAME,
@@ -159,6 +161,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "osrel",              required_argument, NULL, ARG_OSREL              },
                 { "cmdline",            required_argument, NULL, ARG_CMDLINE            },
                 { "initrd",             required_argument, NULL, ARG_INITRD             },
+                { "ucode",              required_argument, NULL, ARG_UCODE              },
                 { "splash",             required_argument, NULL, ARG_SPLASH             },
                 { "dtb",                required_argument, NULL, ARG_DTB                },
                 { "uname",              required_argument, NULL, ARG_UNAME              },
index b1fa04481341029bebf2c7c4a3bac255b82e0d29..3887bf57023ae6a596e6411f393b4e7b593bb22d 100644 (file)
@@ -13,6 +13,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
         [UNIFIED_SECTION_OSREL]   = ".osrel",
         [UNIFIED_SECTION_CMDLINE] = ".cmdline",
         [UNIFIED_SECTION_INITRD]  = ".initrd",
+        [UNIFIED_SECTION_UCODE]   = ".ucode",
         [UNIFIED_SECTION_SPLASH]  = ".splash",
         [UNIFIED_SECTION_DTB]     = ".dtb",
         [UNIFIED_SECTION_UNAME]   = ".uname",
index ffa960f01b4c2abc098efddf755fd07d0e647add..8ab742dd58f3b549e2cb801ec964614d183bd948 100644 (file)
@@ -10,6 +10,7 @@ typedef enum UnifiedSection {
         UNIFIED_SECTION_OSREL,
         UNIFIED_SECTION_CMDLINE,
         UNIFIED_SECTION_INITRD,
+        UNIFIED_SECTION_UCODE,
         UNIFIED_SECTION_SPLASH,
         UNIFIED_SECTION_DTB,
         UNIFIED_SECTION_UNAME,
index d2ec912d496cc7d6db025bb82c32a33ff55688eb..378781c138dce130e9ac916ddc87c87026644d1e 100644 (file)
 /* Pref64 option type (RFC8781, section 4) */
 #define RADV_OPT_PREF64                           38
 
-enum RAdvState {
+typedef enum RAdvState {
         RADV_STATE_IDLE                      = 0,
         RADV_STATE_ADVERTISING               = 1,
-};
-typedef enum RAdvState RAdvState;
+} RAdvState;
 
 struct sd_radv_opt_dns {
         uint8_t type;
@@ -106,6 +105,7 @@ struct sd_radv {
         struct ether_addr mac_addr;
         uint8_t hop_limit;
         uint8_t flags;
+        uint8_t preference;
         uint32_t mtu;
         usec_t retransmit_usec;
         usec_t lifetime_usec; /* timespan */
index 053dd0653b1ad6c33ae23db67230b6ce78a6e8e1..f6f30ce3197764f74e521d4135de82d4fa808246 100644 (file)
@@ -201,7 +201,9 @@ static int radv_send_router(sd_radv *ra, const struct in6_addr *dst) {
         /* The nd_ra_curhoplimit and nd_ra_flags_reserved fields cannot specified with nd_ra_router_lifetime
          * simultaneously in the structured initializer in the above. */
         adv.nd_ra_curhoplimit = ra->hop_limit;
-        adv.nd_ra_flags_reserved = ra->flags;
+        /* RFC 4191, Section 2.2,
+         * "...If the Router Lifetime is zero, the preference value MUST be set to (00) by the sender..." */
+        adv.nd_ra_flags_reserved = ra->flags | (ra->lifetime_usec > 0 ? (ra->preference << 3) : 0);
         iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
 
         /* MAC address is optional, either because the link does not use L2 addresses or load sharing is
@@ -279,11 +281,13 @@ static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
         if (r < 0)
                 return r;
 
-        struct in6_addr src = {};
+        struct in6_addr src;
         r = sd_ndisc_router_solicit_get_sender_address(rs, &src);
-        if (r < 0 && r != -ENODATA) /* null address is allowed */
+        if (r == -ENODATA) /* null address is allowed */
+                return sd_radv_send(ra); /* When an unsolicited RA, we need to also update timer. */
+        if (r < 0)
                 return log_radv_errno(ra, r, "Failed to get sender address of RS, ignoring: %m");
-        if (r >= 0 && in6_addr_equal(&src, &ra->ipv6ll))
+        if (in6_addr_equal(&src, &ra->ipv6ll))
                 /* This should be definitely caused by a misconfiguration. If we send RA to ourself, the
                  * kernel complains about that. Let's ignore the packet. */
                 return log_radv_errno(ra, SYNTHETIC_ERRNO(EADDRINUSE), "Received RS from the same interface, ignoring.");
@@ -314,24 +318,35 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
 }
 
 static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
-        usec_t min_timeout, max_timeout, time_now, timeout;
         sd_radv *ra = ASSERT_PTR(userdata);
+
+        if (sd_radv_send(ra) < 0)
+                (void) sd_radv_stop(ra);
+
+        return 0;
+}
+
+int sd_radv_send(sd_radv *ra) {
+        usec_t min_timeout, max_timeout, time_now, timeout;
         int r;
 
-        assert(s);
-        assert(ra->event);
+        assert_return(ra, -EINVAL);
+        assert_return(ra->event, -EINVAL);
+        assert_return(sd_radv_is_running(ra), -EINVAL);
         assert(router_lifetime_is_valid(ra->lifetime_usec));
 
         r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
         if (r < 0)
-                goto fail;
+                return r;
 
         r = radv_send_router(ra, NULL);
         if (r < 0)
-                log_radv_errno(ra, r, "Unable to send Router Advertisement, ignoring: %m");
+                return log_radv_errno(ra, r, "Unable to send Router Advertisement: %m");
+
+        ra->ra_sent++;
 
         /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
-        if (ra->ra_sent < RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
+        if (ra->ra_sent <= RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
                 max_timeout = RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
         else
                 max_timeout = RADV_DEFAULT_MAX_TIMEOUT_USEC;
@@ -355,34 +370,22 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         assert(min_timeout <= max_timeout * 3 / 4);
 
         timeout = min_timeout + random_u64_range(max_timeout - min_timeout);
-        log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
-
-        r = event_reset_time(ra->event, &ra->timeout_event_source,
-                             CLOCK_BOOTTIME,
-                             usec_add(time_now, timeout), MSEC_PER_SEC,
-                             radv_timeout, ra,
-                             ra->event_priority, "radv-timeout", true);
-        if (r < 0)
-                goto fail;
-
-        ra->ra_sent++;
-
-        return 0;
-
-fail:
-        sd_radv_stop(ra);
-
-        return 0;
+        log_radv(ra, "Sent unsolicited Router Advertisement. Next advertisement will be in %s.",
+                 FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
+
+        return event_reset_time(
+                        ra->event, &ra->timeout_event_source,
+                        CLOCK_BOOTTIME,
+                        usec_add(time_now, timeout), MSEC_PER_SEC,
+                        radv_timeout, ra,
+                        ra->event_priority, "radv-timeout", true);
 }
 
 int sd_radv_stop(sd_radv *ra) {
         int r;
 
-        if (!ra)
-                return 0;
-
-        if (ra->state == RADV_STATE_IDLE)
-                return 0;
+        if (!sd_radv_is_running(ra))
+                return 0; /* Already stopped. */
 
         log_radv(ra, "Stopping IPv6 Router Advertisement daemon");
 
@@ -435,8 +438,8 @@ int sd_radv_start(sd_radv *ra) {
         assert_return(ra->event, -EINVAL);
         assert_return(ra->ifindex > 0, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return 0;
+        if (sd_radv_is_running(ra))
+                return 0; /* Already started. */
 
         r = radv_setup_recv_event(ra);
         if (r < 0)
@@ -464,13 +467,10 @@ int sd_radv_start(sd_radv *ra) {
 
 int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
         assert_return(ra, -EINVAL);
+        assert_return(!sd_radv_is_running(ra), -EBUSY);
         assert_return(ifindex > 0, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         ra->ifindex = ifindex;
-
         return 0;
 }
 
@@ -514,9 +514,6 @@ int sd_radv_set_link_local_address(sd_radv *ra, const struct in6_addr *addr) {
 int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         if (mac_addr)
                 ra->mac_addr = *mac_addr;
         else
@@ -537,23 +534,13 @@ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
 int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         ra->hop_limit = hop_limit;
-
         return 0;
 }
 
 int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
-        if (usec > RADV_MAX_RETRANSMIT_USEC)
-                return -EINVAL;
-
         ra->retransmit_usec = usec;
         return 0;
 }
@@ -561,89 +548,55 @@ int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec) {
 int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         if (!router_lifetime_is_valid(usec))
                 return -EINVAL;
 
-        /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
-         * to (00) by the sender..." */
-        if (usec == 0 &&
-            (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
-                return -EINVAL;
-
         ra->lifetime_usec = usec;
         return 0;
 }
 
-int sd_radv_set_managed_information(sd_radv *ra, int managed) {
+int sd_radv_set_managed_information(sd_radv *ra, int b) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
-        SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
-
+        SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, b);
         return 0;
 }
 
-int sd_radv_set_other_information(sd_radv *ra, int other) {
+int sd_radv_set_other_information(sd_radv *ra, int b) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
-        SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
-
+        SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, b);
         return 0;
 }
 
-int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
+int sd_radv_set_preference(sd_radv *ra, uint8_t preference) {
         assert_return(ra, -EINVAL);
         assert_return(IN_SET(preference,
                              SD_NDISC_PREFERENCE_LOW,
                              SD_NDISC_PREFERENCE_MEDIUM,
                              SD_NDISC_PREFERENCE_HIGH), -EINVAL);
 
-        /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
-         * to (00) by the sender..." */
-        if (ra->lifetime_usec == 0 && preference != SD_NDISC_PREFERENCE_MEDIUM)
-                return -EINVAL;
-
-        ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
-
+        ra->preference = preference;
         return 0;
 }
 
 int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         SET_FLAG(ra->flags, ND_RA_FLAG_HOME_AGENT, home_agent);
-
         return 0;
 }
 
 int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         ra->home_agent.nd_opt_home_agent_info_preference = htobe16(preference);
-
         return 0;
 }
 
 int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
         assert_return(ra, -EINVAL);
 
-        if (ra->state != RADV_STATE_IDLE)
-                return -EBUSY;
-
         if (lifetime_usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC)
                 return -EINVAL;
 
@@ -711,7 +664,7 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
                 log_radv(ra, "Added prefix %s", addr_p);
         }
 
-        if (ra->state == RADV_STATE_IDLE)
+        if (!sd_radv_is_running(ra))
                 return 0;
 
         if (ra->ra_sent == 0)
@@ -807,7 +760,7 @@ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
                 log_radv(ra, "Added route prefix %s", strna(addr_p));
         }
 
-        if (ra->state == RADV_STATE_IDLE)
+        if (!sd_radv_is_running(ra))
                 return 0;
 
         if (ra->ra_sent == 0)
@@ -879,7 +832,7 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
                 log_radv(ra, "Added PREF64 prefix %s", strna(addr_p));
         }
 
-        if (ra->state == RADV_STATE_IDLE)
+        if (!sd_radv_is_running(ra))
                 return 0;
 
         if (ra->ra_sent == 0)
index 76f4d7ba3f2d230188988a159c19b6363673bb40..78635ee657670f22b58cc783ced763f6f14ffe40 100644 (file)
@@ -191,12 +191,6 @@ TEST(radv) {
         assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_HIGH) >= 0);
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_preference(ra, ~0) < 0);
 
-        assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_HIGH) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, 300 * USEC_PER_SEC) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, 0) < 0);
-        assert_se(sd_radv_set_preference(ra, SD_NDISC_PREFERENCE_MEDIUM) >= 0);
-        assert_se(sd_radv_set_router_lifetime(ra, 0) >= 0);
-
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_managed_information(NULL, true) < 0);
         assert_se(sd_radv_set_managed_information(ra, true) >= 0);
         assert_se(sd_radv_set_managed_information(ra, false) >= 0);
@@ -208,7 +202,7 @@ TEST(radv) {
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_retransmit(NULL, 10 * USEC_PER_MSEC) < 0);
         assert_se(sd_radv_set_retransmit(ra, 10 * USEC_PER_MSEC) >= 0);
         assert_se(sd_radv_set_retransmit(ra, 0) >= 0);
-        assert_se(sd_radv_set_retransmit(ra, usec_add(UINT32_MAX * USEC_PER_MSEC, USEC_PER_MSEC)) < 0);
+        assert_se(sd_radv_set_retransmit(ra, USEC_INFINITY) >= 0);
 
         ASSERT_RETURN_EXPECTED_SE(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
         assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
index d23da4c1515c84cd4e54fea36a117c3478d1f9ad..78b4453462935be22843585844a7bfab1c87623a 100644 (file)
@@ -839,5 +839,7 @@ LIBSYSTEMD_256 {
 global:
         sd_bus_creds_get_pidfd_dup;
         sd_bus_creds_new_from_pidfd;
+        sd_id128_get_invocation_app_specific;
         sd_journal_stream_fd_with_namespace;
+        sd_event_source_get_inotify_path;
 } LIBSYSTEMD_255;
index f4e38d78d085b847334df478042697ecbc4b9023..d05bcf0538df633cf97ad0f1d074ec7c2b25f0d8 100644 (file)
@@ -189,6 +189,9 @@ struct inode_data {
          * iteration. */
         int fd;
 
+        /* The path that the fd points to. The field is optional. */
+        char *path;
+
         /* The inotify "watch descriptor" */
         int wd;
 
index 12aa98059381516a805e4eb5fddae02a61d08726..39c60297f06280e11f15c44571dcaae4181d7238 100644 (file)
@@ -2272,6 +2272,7 @@ static void event_free_inode_data(
                 assert_se(hashmap_remove(d->inotify_data->inodes, d) == d);
         }
 
+        free(d->path);
         free(d);
 }
 
@@ -2415,7 +2416,7 @@ static int inode_data_realize_watch(sd_event *e, struct inode_data *d) {
 
         wd = inotify_add_watch_fd(d->inotify_data->fd, d->fd, combined_mask);
         if (wd < 0)
-                return -errno;
+                return wd;
 
         if (d->wd < 0) {
                 r = hashmap_put(d->inotify_data->wd, INT_TO_PTR(wd), d);
@@ -2512,6 +2513,15 @@ static int event_add_inotify_fd_internal(
                 }
 
                 LIST_PREPEND(to_close, e->inode_data_to_close_list, inode_data);
+
+                _cleanup_free_ char *path = NULL;
+                r = fd_get_path(inode_data->fd, &path);
+                if (r < 0 && r != -ENOSYS) { /* The path is optional, hence ignore -ENOSYS. */
+                        event_gc_inode_data(e, inode_data);
+                        return r;
+                }
+
+                free_and_replace(inode_data->path, path);
         }
 
         /* Link our event source to the inode data object */
@@ -2798,6 +2808,13 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
                         }
 
                         LIST_PREPEND(to_close, s->event->inode_data_to_close_list, new_inode_data);
+
+                        _cleanup_free_ char *path = NULL;
+                        r = fd_get_path(new_inode_data->fd, &path);
+                        if (r < 0 && r != -ENOSYS)
+                                goto fail;
+
+                        free_and_replace(new_inode_data->path, path);
                 }
 
                 /* Move the event source to the new inode data structure */
@@ -3282,13 +3299,29 @@ _public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own)
         return 0;
 }
 
-_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) {
+_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret) {
         assert_return(s, -EINVAL);
-        assert_return(mask, -EINVAL);
+        assert_return(ret, -EINVAL);
         assert_return(s->type == SOURCE_INOTIFY, -EDOM);
         assert_return(!event_origin_changed(s->event), -ECHILD);
 
-        *mask = s->inotify.mask;
+        *ret = s->inotify.mask;
+        return 0;
+}
+
+_public_ int sd_event_source_get_inotify_path(sd_event_source *s, const char **ret) {
+        assert_return(s, -EINVAL);
+        assert_return(ret, -EINVAL);
+        assert_return(s->type == SOURCE_INOTIFY, -EDOM);
+        assert_return(!event_origin_changed(s->event), -ECHILD);
+
+        if (!s->inotify.inode_data)
+                return -ESTALE; /* already disconnected. */
+
+        if (!s->inotify.inode_data->path)
+                return -ENOSYS; /* /proc was not mounted? */
+
+        *ret = s->inotify.inode_data->path;
         return 0;
 }
 
index e02de097baa44180489def6a1e23e90ce5349b6c..991aa925a42a7d125ac1b9da386fbe099fb1ecba 100644 (file)
@@ -396,6 +396,7 @@ struct inotify_context {
         unsigned create_called[CREATE_EVENTS_MAX];
         unsigned create_overflow;
         unsigned n_create_events;
+        const char *path;
 };
 
 static void maybe_exit(sd_event_source *s, struct inotify_context *c) {
@@ -422,10 +423,12 @@ static void maybe_exit(sd_event_source *s, struct inotify_context *c) {
 }
 
 static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
-        struct inotify_context *c = userdata;
-        const char *description;
+        struct inotify_context *c = ASSERT_PTR(userdata);
+        const char *path, *description;
         unsigned bit, n;
 
+        assert_se(sd_event_source_get_inotify_path(s, &path) >= 0);
+
         assert_se(sd_event_source_get_description(s, &description) >= 0);
         assert_se(safe_atou(description, &n) >= 0);
 
@@ -433,11 +436,12 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
         bit = 1U << n;
 
         if (ev->mask & IN_Q_OVERFLOW) {
-                log_info("inotify-handler <%s>: overflow", description);
+                log_info("inotify-handler for %s <%s>: overflow", path, description);
                 c->create_overflow |= bit;
         } else if (ev->mask & IN_CREATE) {
+                assert_se(path_equal_or_inode_same(path, c->path, 0));
                 if (streq(ev->name, "sub"))
-                        log_debug("inotify-handler <%s>: create on %s", description, ev->name);
+                        log_debug("inotify-handler for %s <%s>: create on %s", path, description, ev->name);
                 else {
                         unsigned i;
 
@@ -446,7 +450,7 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
                         c->create_called[i] |= bit;
                 }
         } else if (ev->mask & IN_DELETE) {
-                log_info("inotify-handler <%s>: delete of %s", description, ev->name);
+                log_info("inotify-handler for %s <%s>: delete of %s", path, description, ev->name);
                 assert_se(streq(ev->name, "sub"));
         } else
                 assert_not_reached();
@@ -456,16 +460,19 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
 }
 
 static int delete_self_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
-        struct inotify_context *c = userdata;
+        struct inotify_context *c = ASSERT_PTR(userdata);
+        const char *path;
+
+        assert_se(sd_event_source_get_inotify_path(s, &path) >= 0);
 
         if (ev->mask & IN_Q_OVERFLOW) {
-                log_info("delete-self-handler: overflow");
+                log_info("delete-self-handler for %s: overflow", path);
                 c->delete_self_handler_called = true;
         } else if (ev->mask & IN_DELETE_SELF) {
-                log_info("delete-self-handler: delete-self");
+                log_info("delete-self-handler for %s: delete-self", path);
                 c->delete_self_handler_called = true;
         } else if (ev->mask & IN_IGNORED) {
-                log_info("delete-self-handler: ignore");
+                log_info("delete-self-handler for %s: ignore", path);
         } else
                 assert_not_reached();
 
@@ -480,7 +487,7 @@ static void test_inotify_one(unsigned n_create_events) {
                 .n_create_events = n_create_events,
         };
         sd_event *e = NULL;
-        const char *q;
+        const char *q, *pp;
         unsigned i;
 
         log_info("/* %s(%u) */", __func__, n_create_events);
@@ -488,6 +495,7 @@ static void test_inotify_one(unsigned n_create_events) {
         assert_se(sd_event_default(&e) >= 0);
 
         assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0);
+        context.path = p;
 
         assert_se(sd_event_add_inotify(e, &a, p, IN_CREATE|IN_ONLYDIR, inotify_handler, &context) >= 0);
         assert_se(sd_event_add_inotify(e, &b, p, IN_CREATE|IN_DELETE|IN_DONT_FOLLOW, inotify_handler, &context) >= 0);
@@ -500,6 +508,13 @@ static void test_inotify_one(unsigned n_create_events) {
         assert_se(sd_event_source_set_description(b, "1") >= 0);
         assert_se(sd_event_source_set_description(c, "2") >= 0);
 
+        assert_se(sd_event_source_get_inotify_path(a, &pp) >= 0);
+        assert_se(path_equal_or_inode_same(pp, p, 0));
+        assert_se(sd_event_source_get_inotify_path(b, &pp) >= 0);
+        assert_se(path_equal_or_inode_same(pp, p, 0));
+        assert_se(sd_event_source_get_inotify_path(b, &pp) >= 0);
+        assert_se(path_equal_or_inode_same(pp, p, 0));
+
         q = strjoina(p, "/sub");
         assert_se(touch(q) >= 0);
         assert_se(sd_event_add_inotify(e, &d, q, IN_DELETE_SELF, delete_self_handler, &context) >= 0);
index 4336d3f1b709c2a5b43fb7a6e385d453f7feb3aa..62b8aaa347dd2b68e7359b13cc1b65c87fad26f0 100644 (file)
@@ -390,3 +390,16 @@ _public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret)
 
         return sd_id128_get_app_specific(id, app_id, ret);
 }
+
+_public_ int sd_id128_get_invocation_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+        sd_id128_t id;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = sd_id128_get_invocation(&id);
+        if (r < 0)
+                return r;
+
+        return sd_id128_get_app_specific(id, app_id, ret);
+}
index 2e09e715745a5e42240a0e375d53dacc158bb58a..e852591a89140baa6a5d10e795ff76f7829ebc67 100644 (file)
@@ -163,7 +163,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                 int r;
 
                 if (le64toh(o->data.entry_offset) == 0)
-                        warning(offset, "Unused data (entry_offset==0)");
+                        debug(offset, "Unused data (entry_offset==0)");
 
                 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
                         error(offset, "Bad n_entries: %"PRIu64, le64toh(o->data.n_entries));
index a4ed3804d8661aac82d03c3c04fb71cacaeae1e6..713cdcc0ec6323625fbde916131ba03f473089c5 100644 (file)
@@ -1973,7 +1973,7 @@ static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask)
 
         m->wd = inotify_add_watch_fd(j->inotify_fd, fd, mask);
         if (m->wd < 0) {
-                log_debug_errno(errno, "Failed to watch journal directory '%s', ignoring: %m", m->path);
+                log_debug_errno(m->wd, "Failed to watch journal directory '%s', ignoring: %m", m->path);
                 return;
         }
 
index 18c2f9618c004859a2085e4607ea2707e99a9b43..ed1918d10385c4503d774af0b1c68c918e0e2c6f 100644 (file)
@@ -74,9 +74,9 @@ static void test_done(const char *t) {
 }
 
 static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint64_t *seqnum, uint64_t *ret_offset) {
-        _cleanup_free_ char *p = NULL, *q = NULL;
+        _cleanup_free_ char *p = NULL, *q = NULL, *s = NULL;
         dual_timestamp ts;
-        struct iovec iovec[2];
+        struct iovec iovec[3];
         size_t n_iov = 0;
 
         dual_timestamp_now(&ts);
@@ -92,6 +92,9 @@ static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint
         assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
         iovec[n_iov++] = IOVEC_MAKE_STRING(p);
 
+        assert_se(s = strjoin("LESS_THAN_FIVE=%d", yes_no(n < 5)));
+        iovec[n_iov++] = IOVEC_MAKE_STRING(s);
+
         if (boot_id) {
                 assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
                 iovec[n_iov++] = IOVEC_MAKE_STRING(q);
@@ -250,6 +253,37 @@ static void mkdtemp_chdir_chattr(char *path) {
         (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
 }
 
+static void test_cursor(sd_journal *j) {
+        _cleanup_strv_free_ char **cursors = NULL;
+        int r;
+
+        assert_se(sd_journal_seek_head(j) >= 0);
+
+        for (;;) {
+                r = sd_journal_next(j);
+                assert_se(r >= 0);
+                if (r == 0)
+                        break;
+
+                _cleanup_free_ char *cursor = NULL;
+                assert_se(sd_journal_get_cursor(j, &cursor) >= 0);
+                assert_se(sd_journal_test_cursor(j, cursor) > 0);
+                assert_se(strv_consume(&cursors, TAKE_PTR(cursor)) >= 0);
+        }
+
+        STRV_FOREACH(c, cursors) {
+                assert_se(sd_journal_seek_cursor(j, *c) >= 0);
+                assert_se(sd_journal_next(j) >= 0);
+                assert_se(sd_journal_test_cursor(j, *c) > 0);
+        }
+
+        assert_se(sd_journal_seek_head(j) >= 0);
+        STRV_FOREACH(c, cursors) {
+                assert_se(sd_journal_next(j) >= 0);
+                assert_se(sd_journal_test_cursor(j, *c) > 0);
+        }
+}
+
 static void test_skip_one(void (*setup)(void)) {
         char t[] = "/var/tmp/journal-skip-XXXXXX";
         sd_journal *j;
@@ -391,6 +425,30 @@ static void test_skip_one(void (*setup)(void)) {
         test_check_numbers_up(j, 9);
         sd_journal_close(j);
 
+        /* For issue #31516. */
+        assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
+        test_cursor(j);
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+        test_cursor(j);
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=no", SIZE_MAX) >= 0);
+        test_cursor(j);
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=hoge", SIZE_MAX) >= 0);
+        test_cursor(j);
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0);
+        test_cursor(j);
+        sd_journal_flush_matches(j);
+        assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=4", SIZE_MAX) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=5", SIZE_MAX) >= 0);
+        assert_se(sd_journal_add_match(j, "NUMBER=6", SIZE_MAX) >= 0);
+        test_cursor(j);
+
         test_done(t);
 }
 
index 150ce624821f007c4cdd29b41d976d8cc7f7cba3..7078419d3750765095319d030a21b4fcb67f5974 100644 (file)
@@ -31,7 +31,7 @@ UseDomains link_get_use_domains(Link *link, NetworkConfigSource proto) {
         case NETWORK_CONFIG_SOURCE_NDISC:
                 n = link->network->ndisc_use_domains;
                 c = _USE_DOMAINS_INVALID;
-                m = _USE_DOMAINS_INVALID;
+                m = link->manager->ndisc_use_domains;
                 break;
         default:
                 assert_not_reached();
@@ -45,12 +45,16 @@ UseDomains link_get_use_domains(Link *link, NetworkConfigSource proto) {
         if (c >= 0)
                 return c;
 
+        /* If per-network but protocol-independent setting is specified, use it. */
+        if (link->network->use_domains >= 0)
+                return link->network->use_domains;
+
         /* If global per-protocol setting is specified, use it. */
         if (m >= 0)
                 return m;
 
-        /* Otherwise, defaults to no. */
-        return USE_DOMAINS_NO;
+        /* If none of them are specified, use the global protocol-independent value. */
+        return link->manager->use_domains;
 }
 
 bool link_get_use_dns(Link *link, NetworkConfigSource proto) {
index b2d116e98ded182fc932241d2d693998005c0af6..f02dfd7a05f9a87deb876cd2d720a89c88587824 100644 (file)
@@ -31,6 +31,8 @@ Network.RouteTable,                      config_parse_route_table_names,
 Network.IPv4Forwarding,                  config_parse_tristate,                  0,          offsetof(Manager, ip_forwarding[0])
 Network.IPv6Forwarding,                  config_parse_tristate,                  0,          offsetof(Manager, ip_forwarding[1])
 Network.IPv6PrivacyExtensions,           config_parse_ipv6_privacy_extensions,   0,          offsetof(Manager, ipv6_privacy_extensions)
+Network.UseDomains,                      config_parse_use_domains,               0,          offsetof(Manager, use_domains)
+IPv6AcceptRA.UseDomains,                 config_parse_use_domains,               0,          offsetof(Manager, ndisc_use_domains)
 DHCPv4.UseDomains,                       config_parse_use_domains,               0,          offsetof(Manager, dhcp_use_domains)
 DHCPv4.DUIDType,                         config_parse_duid_type,                 0,          offsetof(Manager, dhcp_duid)
 DHCPv4.DUIDRawData,                      config_parse_duid_rawdata,              0,          offsetof(Manager, dhcp_duid)
index 2d21c2bca574f02544f9f25b26c2b4d655cf4c1c..4ec4550caf3cb1f035f101f15dcbdeb96cfb96f8 100644 (file)
@@ -601,6 +601,7 @@ int manager_new(Manager **ret, bool test_mode) {
                 .persistent_storage_fd = persistent_storage_open(),
                 .dhcp_use_domains = _USE_DOMAINS_INVALID,
                 .dhcp6_use_domains = _USE_DOMAINS_INVALID,
+                .ndisc_use_domains = _USE_DOMAINS_INVALID,
                 .dhcp_duid.type = DUID_TYPE_EN,
                 .dhcp6_duid.type = DUID_TYPE_EN,
                 .duid_product_uuid.type = DUID_TYPE_UUID,
index 31ddbdf6174f10fd020725e21913f070014d36bf..c14a98fb9753e13e10d3bf199b76da166404e973 100644 (file)
@@ -64,8 +64,10 @@ struct Manager {
         OrderedSet *address_pools;
         Set *dhcp_pd_subnet_ids;
 
+        UseDomains use_domains; /* default for all protocols */
         UseDomains dhcp_use_domains;
         UseDomains dhcp6_use_domains;
+        UseDomains ndisc_use_domains;
 
         DUID dhcp_duid;
         DUID dhcp6_duid;
index 7084f82f9ff70edc14cc77101fbd5bac7a247f12..62f11c5c5c91823dec1f2c900e3bf37e8bed3e4a 100644 (file)
@@ -118,6 +118,7 @@ Network.EmitLLDP,                            config_parse_lldp_multicast_mode,
 Network.Address,                             config_parse_address,                                     0,                             0
 Network.Gateway,                             config_parse_gateway,                                     0,                             0
 Network.Domains,                             config_parse_domains,                                     0,                             0
+Network.UseDomains,                          config_parse_use_domains,                                 0,                             offsetof(Network, use_domains)
 Network.DNS,                                 config_parse_dns,                                         0,                             0
 Network.DNSDefaultRoute,                     config_parse_tristate,                                    0,                             offsetof(Network, dns_default_route)
 Network.LLMNR,                               config_parse_resolve_support,                             0,                             offsetof(Network, llmnr)
index 15d5721866a373f26f47fefbedd66d1dfc540969..c64091c15aecccae8bf93103d48898d4de07244a 100644 (file)
@@ -377,6 +377,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
 
                 .keep_configuration = manager->keep_configuration,
 
+                .use_domains = _USE_DOMAINS_INVALID,
+
                 .compat_dhcp_use_domains = _USE_DOMAINS_INVALID,
                 .compat_dhcp_use_dns = -1,
                 .compat_dhcp_use_ntp = -1,
@@ -489,6 +491,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .ndisc_use_hop_limit = true,
                 .ndisc_use_reachable_time = true,
                 .ndisc_use_retransmission_time = true,
+                .ndisc_use_domains = _USE_DOMAINS_INVALID,
                 .ndisc_route_table = RT_TABLE_MAIN,
                 .ndisc_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
                 .ndisc_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
index dd938e525aa830663f4659816efe7b779538f0eb..c8573e097342d75fac3db7dc6013bf3db6ea1bc0 100644 (file)
@@ -113,6 +113,9 @@ struct Network {
         bool default_route_on_device;
         AddressFamily ip_masquerade;
 
+        /* Protocol independent settings */
+        UseDomains use_domains;
+
         /* For backward compatibility, only applied to DHCPv4 and DHCPv6. */
         UseDomains compat_dhcp_use_domains;
         int compat_dhcp_use_dns;
index 4291165a913c26d38091f1b4bb372ae648fef388..fa5884a6c354db1b4d35733e4c3c29e862365319 100644 (file)
@@ -627,9 +627,6 @@ static int radv_configure(Link *link) {
 }
 
 int radv_update_mac(Link *link) {
-        bool restart;
-        int r;
-
         assert(link);
 
         if (!link->radv)
@@ -638,23 +635,7 @@ int radv_update_mac(Link *link) {
         if (link->hw_addr.length != ETH_ALEN)
                 return 0;
 
-        restart = sd_radv_is_running(link->radv);
-
-        r = sd_radv_stop(link->radv);
-        if (r < 0)
-                return r;
-
-        r = sd_radv_set_mac(link->radv, &link->hw_addr.ether);
-        if (r < 0)
-                return r;
-
-        if (restart) {
-                r = sd_radv_start(link->radv);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
+        return sd_radv_set_mac(link->radv, &link->hw_addr.ether);
 }
 
 static int radv_is_ready_to_configure(Link *link) {
index 828dbb96388a6230daf564e62da3ab64d6c0d07a..06d436245e7bbe66612d90b24593001fc150b546 100644 (file)
 #ManageForeignNextHops=yes
 #RouteTable=
 #IPv6PrivacyExtensions=no
+#UseDomains=no
+
+[IPv6AcceptRA]
+#UseDomains=
 
 [DHCPv4]
 #DUIDType=vendor
 #DUIDRawData=
-#UseDomains=no
+#UseDomains=
 
 [DHCPv6]
 #DUIDType=vendor
 #DUIDRawData=
-#UseDomains=no
+#UseDomains=
 
 [DHCPServer]
 #PersistLeases=yes
index 2b2720978a7b65117ef63b68ca3a3c2ccf41c0e1..5045ad93e888b8233b584820a4e4c61dce89540b 100644 (file)
@@ -2679,7 +2679,7 @@ static int make_pcrlock_record(
                 assert_se(a = tpm2_hash_alg_to_string(*pa));
                 assert_se(md = EVP_get_digestbyname(a));
                 hash_ssize = EVP_MD_size(md);
-                assert_se(hash_ssize > 0);
+                assert(hash_ssize > 0);
                 hash_usize = hash_ssize;
 
                 hash = malloc(hash_usize);
@@ -2708,6 +2708,101 @@ static int make_pcrlock_record(
         return 0;
 }
 
+static void evp_md_ctx_free_all(EVP_MD_CTX *(*md)[TPM2_N_HASH_ALGORITHMS]) {
+        assert(md);
+        FOREACH_ARRAY(alg, *md, TPM2_N_HASH_ALGORITHMS)
+                if (*alg)
+                        EVP_MD_CTX_free(*alg);
+}
+
+static int make_pcrlock_record_from_stream(
+                uint32_t pcr_mask,
+                FILE *f,
+                JsonVariant **ret_records) {
+
+        _cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
+        _cleanup_(evp_md_ctx_free_all) EVP_MD_CTX *mdctx[TPM2_N_HASH_ALGORITHMS] = {};
+        int r;
+
+        assert(f);
+        assert(ret_records);
+
+        for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
+                const char *a;
+                const EVP_MD *md;
+
+                assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
+                assert_se(md = EVP_get_digestbyname(a));
+
+                mdctx[i] = EVP_MD_CTX_new();
+                if (!mdctx[i])
+                        return log_oom();
+
+                if (EVP_DigestInit_ex(mdctx[i], md, NULL) != 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "Failed to initialize message digest for %s.", a);
+        }
+
+        for (;;) {
+                uint8_t buffer[64*1024];
+                size_t n;
+
+                n = fread(buffer, 1, sizeof(buffer), f);
+                if (ferror(f))
+                        return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to read file: %m");
+                if (n == 0 && feof(f))
+                        break;
+
+                for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++)
+                        if (EVP_DigestUpdate(mdctx[i], buffer, n) != 1)
+                                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
+        }
+
+        for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
+                const char *a;
+                int hash_ssize;
+                unsigned hash_usize;
+
+                assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
+                hash_ssize = EVP_MD_CTX_size(mdctx[i]);
+                assert(hash_ssize > 0 && hash_ssize <= EVP_MAX_MD_SIZE);
+                hash_usize = hash_ssize;
+                unsigned char hash[hash_usize];
+
+                if (EVP_DigestFinal_ex(mdctx[i], hash, &hash_usize) != 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "Failed to finalize hash context for algorithn '%s'.", a);
+
+                r = json_variant_append_arrayb(
+                                &digests,
+                                JSON_BUILD_OBJECT(
+                                                JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
+                                                JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(hash, hash_usize))));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to build JSON digest object: %m");
+        }
+
+        for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
+                _cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
+
+                if (!FLAGS_SET(pcr_mask, UINT32_C(1) << i))
+                        continue;
+
+                r = json_build(&record,
+                               JSON_BUILD_OBJECT(
+                                               JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(i)),
+                                               JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to build record object: %m");
+
+                r = json_variant_append_array(ret_records, record);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to append to JSON array: %m");
+        }
+
+        return 0;
+}
+
 static const char *pcrlock_path(const char *default_pcrlock_path) {
         return arg_pcrlock_path ?: arg_pcrlock_auto ? default_pcrlock_path : NULL;
 }
@@ -2771,10 +2866,8 @@ static int unlink_pcrlock(const char *default_pcrlock_path) {
 }
 
 static int verb_lock_raw(int argc, char *argv[], void *userdata) {
-        _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
-        _cleanup_free_ char *data = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *records = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        size_t size;
         int r;
 
         if (arg_pcr_mask == 0)
@@ -2786,26 +2879,11 @@ static int verb_lock_raw(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
         }
 
-        r = read_full_stream(f ?: stdin, &data, &size);
+        r = make_pcrlock_record_from_stream(arg_pcr_mask, f ?: stdin, &records);
         if (r < 0)
-                return log_error_errno(r, "Failed to read data from stdin: %m");
-
-        for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
-                _cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
-
-                if (!FLAGS_SET(arg_pcr_mask, UINT32_C(1) << i))
-                        continue;
-
-                r = make_pcrlock_record(i, data, size, &record);
-                if (r < 0)
-                        return r;
-
-                r = json_variant_append_array(&array, record);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to append to JSON array: %m");
-        }
+                return r;
 
-        return write_pcrlock(array, NULL);
+        return write_pcrlock(records, NULL);
 }
 
 static int verb_unlock_simple(int argc, char *argv[], void *userdata) {
@@ -3813,10 +3891,9 @@ static int verb_unlock_kernel_cmdline(int argc, char *argv[], void *userdata) {
 }
 
 static int verb_lock_kernel_initrd(int argc, char *argv[], void *userdata) {
-        _cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
-        _cleanup_free_ void *data = NULL;
+        _cleanup_(json_variant_unrefp) JsonVariant *records = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        size_t size;
+        uint32_t pcr_mask = UINT32_C(1) << TPM2_PCR_KERNEL_INITRD;
         int r;
 
         if (argc >= 2) {
@@ -3825,19 +3902,11 @@ static int verb_lock_kernel_initrd(int argc, char *argv[], void *userdata) {
                         return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
         }
 
-        r = read_full_stream(f ?: stdin, (char**) &data, &size);
-        if (r < 0)
-                return log_error_errno(r, "Failed to read data from stdin: %m");
-
-        r = make_pcrlock_record(TPM2_PCR_KERNEL_INITRD /* = 9 */, data, size, &record);
+        r = make_pcrlock_record_from_stream(pcr_mask, f ?: stdin, &records);
         if (r < 0)
                 return r;
 
-        r = json_variant_new_array(&array, &record, 1);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create record array: %m");
-
-        r = write_pcrlock(array, PCRLOCK_KERNEL_INITRD_PATH);
+        r = write_pcrlock(records, PCRLOCK_KERNEL_INITRD_PATH);
         if (r < 0)
                 return r;
 
index 60dc98c5baf313feca9252a499f37ac85ab5621c..53418c417b51d072f0545906a5966534dff345f9 100644 (file)
@@ -43,6 +43,7 @@
 #include "strv.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
+#include "vpick.h"
 
 /* Markers used in the first line of our 20-portable.conf unit file drop-in to determine, that a) the unit file was
  * dropped there by the portable service logic and b) for which image it was dropped there. */
@@ -564,6 +565,7 @@ static int extract_image_and_extensions(
         _cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
+        _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
         _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_strv_free_ char **valid_prefixes = NULL;
         _cleanup_(image_unrefp) Image *image = NULL;
@@ -572,7 +574,27 @@ static int extract_image_and_extensions(
 
         assert(name_or_path);
 
-        r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
+        /* If we get a path, then check if it can be resolved with vpick. We need this as we might just
+         * get a simple image name, which would make vpick error out. */
+        if (path_is_absolute(name_or_path)) {
+                r = path_pick(/* toplevel_path= */ NULL,
+                              /* toplevel_fd= */ AT_FDCWD,
+                              name_or_path,
+                              &pick_filter_image_any,
+                              PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                              &result);
+                if (r < 0)
+                        return r;
+                if (!result.path)
+                        return log_debug_errno(
+                                        SYNTHETIC_ERRNO(ENOENT),
+                                        "No matching entry in .v/ directory %s found.",
+                                        name_or_path);
+
+                name_or_path = result.path;
+        }
+
+        r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
         if (r < 0)
                 return r;
 
@@ -588,9 +610,29 @@ static int extract_image_and_extensions(
                 }
 
                 STRV_FOREACH(p, extension_image_paths) {
+                        _cleanup_(pick_result_done) PickResult ext_result = PICK_RESULT_NULL;
                         _cleanup_(image_unrefp) Image *new = NULL;
+                        const char *path = *p;
+
+                        if (path_is_absolute(*p)) {
+                                r = path_pick(/* toplevel_path= */ NULL,
+                                              /* toplevel_fd= */ AT_FDCWD,
+                                              *p,
+                                              &pick_filter_image_any,
+                                              PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                                              &ext_result);
+                                if (r < 0)
+                                        return r;
+                                if (!ext_result.path)
+                                        return log_debug_errno(
+                                                        SYNTHETIC_ERRNO(ENOENT),
+                                                        "No matching entry in .v/ directory %s found.",
+                                                        *p);
+
+                                path = ext_result.path;
+                        }
 
-                        r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
+                        r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new);
                         if (r < 0)
                                 return r;
 
@@ -1691,6 +1733,7 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
         while (!isempty(marker))
                 STRV_FOREACH(image_name_or_path, root_and_extensions) {
                         _cleanup_free_ char *image = NULL, *base_image = NULL, *base_image_name_or_path = NULL;
+                        _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
 
                         r = extract_first_word(&marker, &image, ":", EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
                         if (r < 0)
@@ -1702,9 +1745,23 @@ static bool marker_matches_images(const char *marker, const char *name_or_path,
                         if (r < 0)
                                 return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image);
 
-                        r = path_extract_image_name(*image_name_or_path, &base_image_name_or_path);
+                        r = path_pick(/* toplevel_path= */ NULL,
+                                      /* toplevel_fd= */ AT_FDCWD,
+                                      *image_name_or_path,
+                                      &pick_filter_image_any,
+                                      PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE,
+                                      &result);
+                        if (r < 0)
+                                return r;
+                        if (!result.path)
+                                return log_debug_errno(
+                                                SYNTHETIC_ERRNO(ENOENT),
+                                                "No matching entry in .v/ directory %s found.",
+                                                *image_name_or_path);
+
+                        r = path_extract_image_name(result.path, &base_image_name_or_path);
                         if (r < 0)
-                                return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", *image_name_or_path);
+                                return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", result.path);
 
                         if (!streq(base_image, base_image_name_or_path)) {
                                 if (match_all)
index fbcee7fc634a80e35edbc1fe10589a3a0d243659..3112ccb677b75041418706a2c0eeca2e011fd719 100644 (file)
@@ -392,9 +392,6 @@ int dnstls_manager_init(Manager *manager) {
 
         assert(manager);
 
-        ERR_load_crypto_strings();
-        SSL_load_error_strings();
-
         manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method());
         if (!manager->dnstls_data.ctx)
                 return -ENOMEM;
index b0cbe3007202325f5847034da9f760dc960f7aea..37d02325b749ea61bc03473e59190abda8fb86ed 100644 (file)
@@ -27,10 +27,11 @@ int clock_get_hwclock(struct tm *tm) {
         if (fd < 0)
                 return -errno;
 
-        /* This leaves the timezone fields of struct tm
-         * uninitialized! */
+        /* This leaves the timezone fields of struct tm uninitialized! */
         if (ioctl(fd, RTC_RD_TIME, tm) < 0)
-                return -errno;
+                /* Some drivers return -EINVAL in case the time could not be kept, i.e. power loss
+                 * happened. Let's turn that into a clearly recognizable error */
+                return errno == EINVAL ? -ENODATA : -errno;
 
         /* We don't know daylight saving, so we reset this in order not
          * to confuse mktime(). */
index b7a97f2b63aa475e20d3b7cae2d5b69ae45772bb..4e7a2049cf4f1fde1e83a2cfd173676df3cb3a29 100644 (file)
@@ -639,7 +639,7 @@ int image_find(ImageClass class,
                                         .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR),
                                         .basename = name,
                                         .architecture = _ARCHITECTURE_INVALID,
-                                        .suffix = suffix,
+                                        .suffix = STRV_MAKE(suffix),
                                 };
 
                                 _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
@@ -807,7 +807,7 @@ int image_discover(
                                                 .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR),
                                                 .basename = pretty,
                                                 .architecture = _ARCHITECTURE_INVALID,
-                                                .suffix = suffix,
+                                                .suffix = STRV_MAKE(suffix),
                                         };
 
                                         _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
index 63c443cbfdde791216316737163abe35d2ebbaf9..dbb6537246a46ceff1a0171921c06dddc12587ef 100644 (file)
 #include "string-util.h"
 
 #if HAVE_OPENSSL
+#  include <openssl/rsa.h>
+#  include <openssl/ec.h>
+
+#  if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+#    include <openssl/engine.h>
+DISABLE_WARNING_DEPRECATED_DECLARATIONS;
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ENGINE*, ENGINE_free, NULL);
+REENABLE_WARNING;
+#  endif
+
 /* For each error in the OpenSSL thread error queue, log the provided message and the OpenSSL error
  * string. If there are no errors in the OpenSSL thread queue, this logs the message with "No OpenSSL
  * errors." This logs at level debug. Returns -EIO (or -ENOMEM). */
@@ -1344,6 +1354,7 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
         assert(private_key_uri);
         assert(ret);
 
+#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
         DISABLE_WARNING_DEPRECATED_DECLARATIONS;
         _cleanup_(ENGINE_freep) ENGINE *e = ENGINE_by_id(engine);
         if (!e)
@@ -1364,6 +1375,9 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
         *ret = TAKE_PTR(private_key);
 
         return 0;
+#else
+        return -EOPNOTSUPP;
+#endif
 }
 
 int openssl_load_key_from_token(
index e5ecbad86d86cc721c78fff9e3e2fab23faa51d6..1a89fcc2bddc4f86d8947fa443b3ec5a7e278831 100644 (file)
@@ -21,7 +21,6 @@ int parse_openssl_key_source_argument(const char *argument, char **private_key_s
 #  include <openssl/bio.h>
 #  include <openssl/bn.h>
 #  include <openssl/crypto.h>
-#  include <openssl/engine.h>
 #  include <openssl/err.h>
 #  include <openssl/evp.h>
 #  include <openssl/opensslv.h>
@@ -54,9 +53,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD_CTX*, EVP_MD_CTX_free, NULL);
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ASN1_OCTET_STRING*, ASN1_OCTET_STRING_free, NULL);
-DISABLE_WARNING_DEPRECATED_DECLARATIONS;
-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ENGINE*, ENGINE_free, NULL);
-REENABLE_WARNING;
+
 #if OPENSSL_VERSION_MAJOR >= 3
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER*, EVP_CIPHER_free, NULL);
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_KDF*, EVP_KDF_free, NULL);
index 41177f821e6708874731e990adbec87cc25c75be..9169513e09cea2c9a3767d87e61d5f4950700b76 100644 (file)
@@ -116,8 +116,7 @@ bool slow_tests_enabled(void) {
 void test_setup_logging(int level) {
         log_set_assert_return_is_critical(true);
         log_set_max_level(level);
-        log_parse_environment();
-        log_open();
+        log_setup();
 }
 
 int write_tmpfile(char *pattern, const char *contents) {
@@ -190,12 +189,16 @@ static int allocate_scope(void) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        _cleanup_free_ char *scope = NULL;
+        _cleanup_free_ char *scope = NULL, *cgroup_root = NULL;
         const char *object;
         int r;
 
         /* Let's try to run this test in a scope of its own, with delegation turned on, so that PID 1 doesn't
          * interfere with our cgroup management. */
+        if (cg_pid_get_path(NULL, 0, &cgroup_root) >= 0 && cg_is_delegated(cgroup_root) && stderr_is_journal()) {
+                log_debug("Already running as a unit with delegated cgroup, not allocating a cgroup subroot.");
+                return 0;
+        }
 
         r = sd_bus_default_system(&bus);
         if (r < 0)
index 784748545c28cb3b81860df2ea2ce1a339819f38..09fdfd6b75c81d205a1977397fe839c466c02075 100644 (file)
@@ -8,6 +8,7 @@
 #include "sd-daemon.h"
 
 #include "argv-util.h"
+#include "errno-util.h"
 #include "macro.h"
 #include "process-util.h"
 #include "rlimit-util.h"
@@ -226,6 +227,36 @@ static inline int run_test_table(void) {
                 }                                                                                               \
         })
 
+#define ASSERT_ERROR(expr1, expr2)                                                                              \
+        ({                                                                                                      \
+                int _expr1 = (expr1);                                                                           \
+                int _expr2 = (expr2);                                                                           \
+                if (_expr1 >= 0) {                                                                              \
+                        log_error("%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but it succeeded", \
+                                  PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2));                            \
+                        abort();                                                                                \
+                } else if (-_expr1 != _expr2) {                                                                  \
+                        log_error_errno(_expr1, "%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but got the following error: %m", \
+                                        PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2));                      \
+                        abort();                                                                                \
+                }                                                                                               \
+        })
+
+#define ASSERT_ERROR_ERRNO(expr1, expr2)                                                                        \
+        ({                                                                                                      \
+                int _expr1 = (expr1);                                                                           \
+                int _expr2 = (expr2);                                                                           \
+                if (_expr1 >= 0) {                                                                              \
+                        log_error("%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but it succeeded", \
+                                  PROJECT_FILE, __LINE__, #expr1, STRERROR(_expr2));                            \
+                        abort();                                                                                \
+                } else if (errno != _expr2) {                                                                   \
+                        log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to fail with error \"%s\", but got the following error: %m", \
+                                        PROJECT_FILE, __LINE__, #expr1, STRERROR(errno));                       \
+                        abort();                                                                                \
+                }                                                                                               \
+        })
+
 #define ASSERT_TRUE(expr)                                                                                       \
         ({                                                                                                      \
                 if (!(expr)) {                                                                                  \
index 7ec9c9a9747504829314bb490dfcd3f804447923..1e747a07e49252b59830656526c7988c3ec8033f 100644 (file)
 #include "tpm2-util.h"
 #include "virt.h"
 
+#if HAVE_OPENSSL
+#  include <openssl/hmac.h>
+#endif
+
 #if HAVE_TPM2
 static void *libtss2_esys_dl = NULL;
 static void *libtss2_rc_dl = NULL;
index 1870fb97ef7ed6aad4ea5306680d423f6ac48fb9..4720e7448d8acfedd4492a8a022c1ecbe801ecfb 100644 (file)
@@ -34,6 +34,8 @@ static int format_fname(
 
         if (FLAGS_SET(flags, PICK_TRIES) || !filter->version) /* Underspecified? */
                 return -ENOEXEC;
+        if (strv_length(filter->suffix) > 1) /* suffix is not deterministic? */
+                return -ENOEXEC;
 
         /* The format for names we match goes like this:
          *
@@ -85,8 +87,9 @@ static int format_fname(
                         return -ENOMEM;
         }
 
-        if (filter->suffix && !strextend(&fn, filter->suffix))
-                return -ENOMEM;
+        if (!strv_isempty(filter->suffix))
+                if (!strextend(&fn, filter->suffix[0]))
+                        return -ENOMEM;
 
         if (!filename_is_valid(fn))
                 return -EINVAL;
@@ -180,11 +183,9 @@ static int pin_choice(
         if (!result.path)
                 return log_oom_debug();
 
-        if (filter->version) {
-                result.version = strdup(filter->version);
-                if (!result.version)
-                        return log_oom_debug();
-        }
+        r = strdup_to(&result.version, filter->version);
+        if (r < 0)
+                return r;
 
         *ret = TAKE_PICK_RESULT(result);
         return 1;
@@ -289,13 +290,12 @@ static int make_choice(
                         return log_oom_debug();
 
                 r = chaseat(toplevel_fd, p, CHASE_AT_RESOLVE_IN_ROOT, &object_path, &object_fd);
-                if (r < 0) {
-                        if (r != -ENOENT)
-                                return log_debug_errno(r, "Failed to open '%s': %m", prefix_roota(toplevel_path, p));
-
+                if (r == -ENOENT) {
                         *ret = PICK_RESULT_NULL;
                         return 0;
                 }
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to open '%s': %m", prefix_roota(toplevel_path, p));
 
                 return pin_choice(
                                 toplevel_path,
@@ -352,8 +352,8 @@ static int make_choice(
                 } else
                         e = dname;
 
-                if (!isempty(filter->suffix)) {
-                        char *sfx = endswith(e, filter->suffix);
+                if (!strv_isempty(filter->suffix)) {
+                        char *sfx = endswith_strv(e, filter->suffix);
                         if (!sfx)
                                 continue;
 
@@ -493,7 +493,8 @@ int path_pick(
                 PickResult *ret) {
 
         _cleanup_free_ char *filter_bname = NULL, *dir = NULL, *parent = NULL, *fname = NULL;
-        const char *filter_suffix, *enumeration_path;
+        char * const *filter_suffix_strv = NULL;
+        const char *filter_suffix = NULL, *enumeration_path;
         uint32_t filter_type_mask;
         int r;
 
@@ -549,14 +550,12 @@ int path_pick(
                 if (!filter_bname)
                         return -ENOMEM;
 
-                if (filter->suffix) {
-                        /* Chop off suffix, if specified */
-                        char *f = endswith(filter_bname, filter->suffix);
-                        if (f)
-                                *f = 0;
-                }
+                /* Chop off suffix, if specified */
+                char *f = endswith_strv(filter_bname, filter->suffix);
+                if (f)
+                        *f = 0;
 
-                filter_suffix = filter->suffix;
+                filter_suffix_strv = filter->suffix;
                 filter_type_mask = filter->type_mask;
 
                 enumeration_path = path;
@@ -616,7 +615,7 @@ int path_pick(
                                 .basename = filter_bname,
                                 .version = filter->version,
                                 .architecture = filter->architecture,
-                                .suffix = filter_suffix,
+                                .suffix = filter_suffix_strv ?: STRV_MAKE(filter_suffix),
                         },
                         flags,
                         ret);
@@ -685,10 +684,16 @@ int path_pick_update_warn(
 const PickFilter pick_filter_image_raw = {
         .type_mask = (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK),
         .architecture = _ARCHITECTURE_INVALID,
-        .suffix = ".raw",
+        .suffix = STRV_MAKE(".raw"),
 };
 
 const PickFilter pick_filter_image_dir = {
         .type_mask = UINT32_C(1) << DT_DIR,
         .architecture = _ARCHITECTURE_INVALID,
 };
+
+const PickFilter pick_filter_image_any = {
+        .type_mask = (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) | (UINT32_C(1) << DT_DIR),
+        .architecture = _ARCHITECTURE_INVALID,
+        .suffix = STRV_MAKE(".raw", ""),
+};
index 21ce6684041efcaa02e58b744fde5432bf47801f..38251c84e8576706012b1d829332bba12809eb1a 100644 (file)
@@ -16,7 +16,7 @@ typedef struct PickFilter {
         const char *basename;         /* Can be overridden by search pattern */
         const char *version;
         Architecture architecture;
-        const char *suffix;           /* Can be overridden by search pattern */
+        char * const *suffix;         /* Can be overridden by search pattern */
 } PickFilter;
 
 typedef struct PickResult {
@@ -58,3 +58,4 @@ int path_pick_update_warn(
 
 extern const PickFilter pick_filter_image_raw;
 extern const PickFilter pick_filter_image_dir;
+extern const PickFilter pick_filter_image_any;
index 49d69759674c7780be7b3f62b092935bcecb2afa..a876add00c12c681711a270bafd71c0df1a059a7 100644 (file)
@@ -161,6 +161,7 @@ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo
 int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags);
 #endif
 int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret);
+int sd_event_source_get_inotify_path(sd_event_source *s, const char **ret);
 int sd_event_source_set_memory_pressure_type(sd_event_source *e, const char *ty);
 int sd_event_source_set_memory_pressure_period(sd_event_source *s, uint64_t threshold_usec, uint64_t window_usec);
 int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback);
index a984a9d85e15ca37b989b83a2a0a46184d8b5c15..a9210526b6a4bf37b13f7d730c7709a1e5c5a11e 100644 (file)
@@ -53,6 +53,7 @@ int sd_id128_get_invocation(sd_id128_t *ret);
 int sd_id128_get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret);
 int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
 int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
+int sd_id128_get_invocation_app_specific(sd_id128_t app_id, sd_id128_t *ret);
 
 #define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
         { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \
index 6d17dcc7f6d82dd81d29032e15d874209c71e8eb..f25622fceb5d844fc66a7bdfe15700a61d770727 100644 (file)
@@ -48,6 +48,7 @@ sd_event *sd_radv_get_event(sd_radv *ra);
 int sd_radv_start(sd_radv *ra);
 int sd_radv_stop(sd_radv *ra);
 int sd_radv_is_running(sd_radv *ra);
+int sd_radv_send(sd_radv *ra);
 
 int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
 int sd_radv_set_ifname(sd_radv *ra, const char *interface_name);
@@ -58,9 +59,9 @@ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu);
 int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit);
 int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec);
 int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec);
-int sd_radv_set_managed_information(sd_radv *ra, int managed);
-int sd_radv_set_other_information(sd_radv *ra, int other);
-int sd_radv_set_preference(sd_radv *ra, unsigned preference);
+int sd_radv_set_managed_information(sd_radv *ra, int b);
+int sd_radv_set_other_information(sd_radv *ra, int b);
+int sd_radv_set_preference(sd_radv *ra, uint8_t preference);
 int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
 int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p);
 int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p);
index e18130b42352a30e919e83862cce2ed64b82f34d..cc677740d8f984017a5da1eb653f9f3734f12094 100644 (file)
@@ -50,6 +50,10 @@ int main(int argc, char *argv[]) {
         if (r == -ENOMEDIUM)
                 return log_tests_skipped("cgroupfs not available");
 
+        r = find_executable("ping", NULL);
+        if (r < 0)
+                return log_tests_skipped_errno(r, "Can't find ping binary: %m");
+
         _cleanup_free_ char *unit_dir = NULL;
         ASSERT_OK(get_testdata_dir("units", &unit_dir));
         ASSERT_OK(set_unit_path(unit_dir));
index c9962501db2cb335a65b397e2d53c5e0852693e5..f42ca4edb9ceaa2b04586620157b7c3019c23572 100644 (file)
@@ -90,12 +90,12 @@ int main(int argc, char *argv[]) {
         ASSERT_OK(manager_startup(m, NULL, NULL, NULL));
 
         /* We need to enable access to the filesystem where the binary is so we
-         * add @common-block */
-        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("@common-block")), 0);
-        ASSERT_OK(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("tracefs", "@common-block")));
-        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("tracefs", "@common-block", "~tracefs")), 0);
-        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/debug/sleep_time", STRV_MAKE("@common-block")), 0);
-        ASSERT_OK(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/debug/sleep_time", STRV_MAKE("debugfs", "@common-block")));
+         * add @common-block and @application */
+        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("@common-block", "@application")), 0);
+        ASSERT_OK(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("tracefs", "@common-block", "@application")));
+        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/tracing/printk_formats", STRV_MAKE("tracefs", "@common-block", "@application", "~tracefs")), 0);
+        ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/debug/sleep_time", STRV_MAKE("@common-block", "@application")), 0);
+        ASSERT_OK(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/debug/sleep_time", STRV_MAKE("debugfs", "@common-block", "@application")));
         ASSERT_LT(test_restrict_filesystems(m, "restrict_filesystems_test.service", "/sys/kernel/debug/sleep_time", STRV_MAKE("~debugfs")), 0);
 
         return 0;
index e9b922b42ef34d5b8bb7d665a4b7701aac0aab76..23eefcdf4b06cbd6aaf31671dac7a2ae897ab659 100644 (file)
@@ -59,8 +59,8 @@ static void wait_for_service_finish(Manager *m, Unit *unit) {
         usec_t ts;
         usec_t timeout = 2 * USEC_PER_MINUTE;
 
-        assert_se(m);
-        assert_se(unit);
+        ASSERT_NOT_NULL(m);
+        ASSERT_NOT_NULL(unit);
 
         /* Bump the timeout when running in plain QEMU, as some more involved tests might start hitting the
          * default 2m timeout (like exec-dynamicuser-statedir.service) */
@@ -76,7 +76,7 @@ static void wait_for_service_finish(Manager *m, Unit *unit) {
                 usec_t n;
 
                 r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
-                assert_se(r >= 0);
+                ASSERT_OK(r);
 
                 n = now(CLOCK_MONOTONIC);
                 if (ts + timeout < n) {
@@ -93,8 +93,8 @@ static void check_main_result(const char *file, unsigned line, const char *func,
                               Manager *m, Unit *unit, int status_expected, int code_expected) {
         Service *service = NULL;
 
-        assert_se(m);
-        assert_se(unit);
+        ASSERT_NOT_NULL(m);
+        ASSERT_NOT_NULL(unit);
 
         wait_for_service_finish(m, unit);
 
@@ -120,8 +120,8 @@ static void check_service_result(const char *file, unsigned line, const char *fu
                                  Manager *m, Unit *unit, ServiceResult result_expected) {
         Service *service = NULL;
 
-        assert_se(m);
-        assert_se(unit);
+        ASSERT_NOT_NULL(m);
+        ASSERT_NOT_NULL(unit);
 
         wait_for_service_finish(m, unit);
 
@@ -185,7 +185,7 @@ static bool check_user_has_group_with_same_name(const char *name) {
         struct passwd *p;
         struct group *g;
 
-        assert_se(name);
+        ASSERT_NOT_NULL(name);
 
         p = getpwnam(name);
         if (!p ||
@@ -221,7 +221,8 @@ static void start_parent_slices(Unit *unit) {
         if (slice) {
                 start_parent_slices(slice);
                 int r = unit_start(slice, NULL);
-                assert_se(r >= 0 || r == -EALREADY);
+                if (r != -EALREADY)
+                        ASSERT_OK(r);
         }
 }
 
@@ -254,7 +255,7 @@ static bool have_userns_privileges(void) {
                       FORK_CLOSE_ALL_FDS |
                       FORK_DEATHSIG_SIGKILL,
                       &pid);
-        assert(r >= 0);
+        ASSERT_OK(r);
         if (r == 0) {
                 /* Keep CAP_SYS_ADMIN if we have it to ensure we give an
                  * accurate result to the caller. Some kernels have a
@@ -290,13 +291,13 @@ static void _test(const char *file, unsigned line, const char *func,
                   Manager *m, const char *unit_name, int status_expected, int code_expected) {
         Unit *unit;
 
-        assert_se(unit_name);
+        ASSERT_NOT_NULL(unit_name);
 
-        assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
+        ASSERT_OK(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit));
         /* We need to start the slices as well otherwise the slice cgroups might be pruned
          * in on_cgroup_empty_event. */
         start_parent_slices(unit);
-        assert_se(unit_start(unit, NULL) >= 0);
+        ASSERT_OK(unit_start(unit, NULL));
         check_main_result(file, line, func, m, unit, status_expected, code_expected);
 
         ++n_ran_tests;
@@ -308,18 +309,18 @@ static void _test_service(const char *file, unsigned line, const char *func,
                           Manager *m, const char *unit_name, ServiceResult result_expected) {
         Unit *unit;
 
-        assert_se(unit_name);
+        ASSERT_NOT_NULL(unit_name);
 
-        assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
-        assert_se(unit_start(unit, NULL) >= 0);
+        ASSERT_OK(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit));
+        ASSERT_OK(unit_start(unit, NULL));
         check_service_result(file, line, func, m, unit, result_expected);
 }
 #define test_service(m, unit_name, result_expected) \
         _test_service(PROJECT_FILE, __LINE__, __func__, m, unit_name, result_expected)
 
 static void test_exec_bindpaths(Manager *m) {
-        assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
-        assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
+        ASSERT_OK(mkdir_p("/tmp/test-exec-bindpaths", 0755));
+        ASSERT_OK(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755));
 
         test(m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
@@ -330,8 +331,8 @@ static void test_exec_bindpaths(Manager *m) {
 static void test_exec_cpuaffinity(Manager *m) {
         _cleanup_(cpu_set_reset) CPUSet c = {};
 
-        assert_se(cpu_set_realloc(&c, 8192) >= 0); /* just allocate the maximum possible size */
-        assert_se(sched_getaffinity(0, c.allocated, c.set) >= 0);
+        ASSERT_OK(cpu_set_realloc(&c, 8192)); /* just allocate the maximum possible size */
+        ASSERT_OK_ERRNO(sched_getaffinity(0, c.allocated, c.set));
 
         if (!CPU_ISSET_S(0, c.allocated, c.set)) {
                 log_notice("Cannot use CPU 0, skipping %s", __func__);
@@ -357,7 +358,7 @@ static void test_exec_credentials(Manager *m) {
 }
 
 static void test_exec_workingdirectory(Manager *m) {
-        assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
+        ASSERT_OK(mkdir_p("/tmp/test-exec_workingdirectory", 0755));
 
         test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
         test(m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
@@ -366,13 +367,13 @@ static void test_exec_workingdirectory(Manager *m) {
 }
 
 static void test_exec_execsearchpath(Manager *m) {
-        assert_se(mkdir_p("/tmp/test-exec_execsearchpath", 0755) >= 0);
+        ASSERT_OK(mkdir_p("/tmp/test-exec_execsearchpath", 0755));
 
-        assert_se(copy_file("/bin/ls", "/tmp/test-exec_execsearchpath/ls_temp", 0,  0777, COPY_REPLACE) >= 0);
+        ASSERT_OK(copy_file("/bin/ls", "/tmp/test-exec_execsearchpath/ls_temp", 0,  0777, COPY_REPLACE));
 
         test(m, "exec-execsearchpath.service", 0, CLD_EXITED);
 
-        assert_se(rm_rf("/tmp/test-exec_execsearchpath", REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+        ASSERT_OK(rm_rf("/tmp/test-exec_execsearchpath", REMOVE_ROOT|REMOVE_PHYSICAL));
 
         test(m, "exec-execsearchpath.service", EXIT_EXEC, CLD_EXITED);
 }
@@ -415,8 +416,7 @@ static void test_exec_execsearchpath_environment_files(Manager *m) {
         int r;
 
         r = write_string_file("/tmp/test-exec_execsearchpath_environmentfile.conf", path_not_set, WRITE_STRING_FILE_CREATE);
-
-        assert_se(r == 0);
+        ASSERT_OK(r);
 
         test(m, "exec-execsearchpath-environmentfile.service", 0, CLD_EXITED);
 
@@ -424,8 +424,7 @@ static void test_exec_execsearchpath_environment_files(Manager *m) {
 
 
         r = write_string_file("/tmp/test-exec_execsearchpath_environmentfile-set.conf", path_set, WRITE_STRING_FILE_CREATE);
-
-        assert_se(r == 0);
+        ASSERT_OK(r);
 
         test(m, "exec-execsearchpath-environmentfile-set.service", 0, CLD_EXITED);
 
@@ -433,23 +432,23 @@ static void test_exec_execsearchpath_environment_files(Manager *m) {
 }
 
 static void test_exec_execsearchpath_passenvironment(Manager *m) {
-        assert_se(setenv("VAR1", "word1 word2", 1) == 0);
-        assert_se(setenv("VAR2", "word3", 1) == 0);
-        assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
-        assert_se(setenv("VAR4", "new\nline", 1) == 0);
-        assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
+        ASSERT_OK_ERRNO(setenv("VAR1", "word1 word2", 1));
+        ASSERT_OK_ERRNO(setenv("VAR2", "word3", 1));
+        ASSERT_OK_ERRNO(setenv("VAR3", "$word 5 6", 1));
+        ASSERT_OK_ERRNO(setenv("VAR4", "new\nline", 1));
+        ASSERT_OK_ERRNO(setenv("VAR5", "passwordwithbackslashes", 1));
 
         test(m, "exec-execsearchpath-passenvironment.service", 0, CLD_EXITED);
 
-        assert_se(setenv("PATH", "/usr", 1) == 0);
+        ASSERT_OK_ERRNO(setenv("PATH", "/usr", 1));
         test(m, "exec-execsearchpath-passenvironment-set.service", 0, CLD_EXITED);
 
-        assert_se(unsetenv("VAR1") == 0);
-        assert_se(unsetenv("VAR2") == 0);
-        assert_se(unsetenv("VAR3") == 0);
-        assert_se(unsetenv("VAR4") == 0);
-        assert_se(unsetenv("VAR5") == 0);
-        assert_se(unsetenv("PATH") == 0);
+        ASSERT_OK_ERRNO(unsetenv("VAR1"));
+        ASSERT_OK_ERRNO(unsetenv("VAR2"));
+        ASSERT_OK_ERRNO(unsetenv("VAR3"));
+        ASSERT_OK_ERRNO(unsetenv("VAR4"));
+        ASSERT_OK_ERRNO(unsetenv("VAR5"));
+        ASSERT_OK_ERRNO(unsetenv("PATH"));
 }
 
 static void test_exec_personality(Manager *m) {
@@ -487,7 +486,7 @@ static void test_exec_ignoresigpipe(Manager *m) {
 }
 
 static void test_exec_privatetmp(Manager *m) {
-        assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
+        ASSERT_OK(touch("/tmp/test-exec_privatetmp"));
 
         if (MANAGER_IS_SYSTEM(m) || have_userns_privileges()) {
                 test(m, "exec-privatetmp-yes.service", can_unshare ? 0 : MANAGER_IS_SYSTEM(m) ? EXIT_FAILURE : EXIT_NAMESPACE, CLD_EXITED);
@@ -621,8 +620,8 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
         char buf[4096];
         ssize_t l;
 
-        assert_se(s);
-        assert_se(fd >= 0);
+        ASSERT_NOT_NULL(s);
+        ASSERT_GT(fd, 0);
 
         l = read(fd, buf, sizeof(buf) - 1);
         if (l < 0) {
@@ -636,20 +635,20 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
 
         buf[l] = '\0';
         if (result)
-                assert_se(strextend(result, buf));
+                ASSERT_NOT_NULL(strextend(result, buf));
         else
                 log_error("ldd: %s", buf);
 
 reenable:
         /* Re-enable the event source if we did not encounter EOF */
-        assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
+        ASSERT_OK(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT));
         return 0;
 }
 
 static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
         pid_t *pid = userdata;
 
-        assert_se(pid);
+        ASSERT_NOT_NULL(pid);
 
         (void) kill(*pid, SIGKILL);
 
@@ -659,7 +658,7 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
 static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
         int ret = -EIO;
 
-        assert_se(si);
+        ASSERT_NOT_NULL(si);
 
         if (si->si_code == CLD_EXITED)
                 ret = si->si_status;
@@ -679,19 +678,19 @@ static int find_libraries(const char *exec, char ***ret) {
         pid_t pid;
         int r;
 
-        assert_se(exec);
-        assert_se(ret);
+        ASSERT_NOT_NULL(exec);
+        ASSERT_NOT_NULL(ret);
 
-        assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
+        ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
 
-        assert_se(pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) == 0);
-        assert_se(pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) == 0);
+        ASSERT_OK_ERRNO(pipe2(outpipe, O_NONBLOCK|O_CLOEXEC));
+        ASSERT_OK_ERRNO(pipe2(errpipe, O_NONBLOCK|O_CLOEXEC));
 
         r = safe_fork_full("(spawn-ldd)",
                            (int[]) { -EBADF, outpipe[1], errpipe[1] },
                            NULL, 0,
                            FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG, &pid);
-        assert_se(r >= 0);
+        ASSERT_OK(r);
         if (r == 0) {
                 execlp("ldd", "ldd", exec, NULL);
                 _exit(EXIT_FAILURE);
@@ -700,40 +699,40 @@ static int find_libraries(const char *exec, char ***ret) {
         outpipe[1] = safe_close(outpipe[1]);
         errpipe[1] = safe_close(errpipe[1]);
 
-        assert_se(sd_event_new(&e) >= 0);
+        ASSERT_OK(sd_event_new(&e));
 
-        assert_se(sd_event_add_time_relative(e, NULL, CLOCK_MONOTONIC,
-                                             10 * USEC_PER_SEC, USEC_PER_SEC, on_spawn_timeout, &pid) >= 0);
-        assert_se(sd_event_add_io(e, &stdout_source, outpipe[0], EPOLLIN, on_spawn_io, &result) >= 0);
-        assert_se(sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT) >= 0);
-        assert_se(sd_event_add_io(e, &stderr_source, errpipe[0], EPOLLIN, on_spawn_io, NULL) >= 0);
-        assert_se(sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT) >= 0);
-        assert_se(sd_event_add_child(e, &sigchld_source, pid, WEXITED, on_spawn_sigchld, NULL) >= 0);
+        ASSERT_OK(sd_event_add_time_relative(e, NULL, CLOCK_MONOTONIC,
+                                             10 * USEC_PER_SEC, USEC_PER_SEC, on_spawn_timeout, &pid));
+        ASSERT_OK(sd_event_add_io(e, &stdout_source, outpipe[0], EPOLLIN, on_spawn_io, &result));
+        ASSERT_OK(sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT));
+        ASSERT_OK(sd_event_add_io(e, &stderr_source, errpipe[0], EPOLLIN, on_spawn_io, NULL));
+        ASSERT_OK(sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT));
+        ASSERT_OK(sd_event_add_child(e, &sigchld_source, pid, WEXITED, on_spawn_sigchld, NULL));
         /* SIGCHLD should be processed after IO is complete */
-        assert_se(sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1) >= 0);
+        ASSERT_OK(sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1));
 
-        assert_se(sd_event_loop(e) >= 0);
+        ASSERT_OK(sd_event_loop(e));
 
         _cleanup_strv_free_ char **v = NULL;
-        assert_se(strv_split_newlines_full(&v, result, 0) >= 0);
+        ASSERT_OK(strv_split_newlines_full(&v, result, 0));
 
         STRV_FOREACH(q, v) {
                 _cleanup_free_ char *word = NULL;
                 const char *p = *q;
 
                 r = extract_first_word(&p, &word, NULL, 0);
-                assert_se(r >= 0);
+                ASSERT_OK(r);
                 if (r == 0)
                         continue;
 
                 if (path_is_absolute(word)) {
-                        assert_se(strv_consume(&libraries, TAKE_PTR(word)) >= 0);
+                        ASSERT_OK(strv_consume(&libraries, TAKE_PTR(word)));
                         continue;
                 }
 
                 word = mfree(word);
                 r = extract_first_word(&p, &word, NULL, 0);
-                assert_se(r >= 0);
+                ASSERT_OK(r);
                 if (r == 0)
                         continue;
 
@@ -742,12 +741,12 @@ static int find_libraries(const char *exec, char ***ret) {
 
                 word = mfree(word);
                 r = extract_first_word(&p, &word, NULL, 0);
-                assert_se(r >= 0);
+                ASSERT_OK(r);
                 if (r == 0)
                         continue;
 
                 if (path_is_absolute(word)) {
-                        assert_se(strv_consume(&libraries, TAKE_PTR(word)) >= 0);
+                        ASSERT_OK(strv_consume(&libraries, TAKE_PTR(word)));
                         continue;
                 }
         }
@@ -761,7 +760,7 @@ static void test_exec_mount_apivfs(Manager *m) {
         _cleanup_strv_free_ char **libraries = NULL, **libraries_test = NULL;
         int r;
 
-        assert_se(user_runtime_unit_dir);
+        ASSERT_NOT_NULL(user_runtime_unit_dir);
 
         r = find_executable("ldd", NULL);
         if (r < 0) {
@@ -782,22 +781,22 @@ static void test_exec_mount_apivfs(Manager *m) {
         if (MANAGER_IS_USER(m) && !have_userns_privileges())
                 return (void)log_notice("Skipping %s, do not have user namespace privileges", __func__);
 
-        assert_se(find_libraries(fullpath_touch, &libraries) >= 0);
-        assert_se(find_libraries(fullpath_test, &libraries_test) >= 0);
-        assert_se(strv_extend_strv(&libraries, libraries_test, true) >= 0);
+        ASSERT_OK(find_libraries(fullpath_touch, &libraries));
+        ASSERT_OK(find_libraries(fullpath_test, &libraries_test));
+        ASSERT_OK(strv_extend_strv(&libraries, libraries_test, true));
 
-        assert_se(strextend(&data, "[Service]\n"));
-        assert_se(strextend(&data, "ExecStart=", fullpath_touch, " /aaa\n"));
-        assert_se(strextend(&data, "ExecStart=", fullpath_test, " -f /aaa\n"));
-        assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_touch, "\n"));
-        assert_se(strextend(&data, "BindReadOnlyPaths=", fullpath_test, "\n"));
+        ASSERT_NOT_NULL(strextend(&data, "[Service]\n"));
+        ASSERT_NOT_NULL(strextend(&data, "ExecStart=", fullpath_touch, " /aaa\n"));
+        ASSERT_NOT_NULL(strextend(&data, "ExecStart=", fullpath_test, " -f /aaa\n"));
+        ASSERT_NOT_NULL(strextend(&data, "BindReadOnlyPaths=", fullpath_touch, "\n"));
+        ASSERT_NOT_NULL(strextend(&data, "BindReadOnlyPaths=", fullpath_test, "\n"));
 
         STRV_FOREACH(p, libraries)
-                assert_se(strextend(&data, "BindReadOnlyPaths=", *p, "\n"));
+                ASSERT_NOT_NULL(strextend(&data, "BindReadOnlyPaths=", *p, "\n"));
 
-        assert_se(write_drop_in(user_runtime_unit_dir, "exec-mount-apivfs-no.service", 10, "bind-mount", data) >= 0);
+        ASSERT_OK(write_drop_in(user_runtime_unit_dir, "exec-mount-apivfs-no.service", 10, "bind-mount", data));
 
-        assert_se(mkdir_p("/tmp/test-exec-mount-apivfs-no/root", 0755) >= 0);
+        ASSERT_OK(mkdir_p("/tmp/test-exec-mount-apivfs-no/root", 0755));
 
         test(m, "exec-mount-apivfs-no.service", can_unshare || !MANAGER_IS_SYSTEM(m) ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
@@ -977,7 +976,7 @@ static char* private_directory_bad(Manager *m) {
                 _cleanup_free_ char *p = NULL;
                 struct stat st;
 
-                assert_se(p = path_join(m->prefix[dt], "private"));
+                ASSERT_NOT_NULL(p = path_join(m->prefix[dt], "private"));
 
                 if (stat(p, &st) >= 0 &&
                     (st.st_mode & (S_IRWXG|S_IRWXO)))
@@ -1055,7 +1054,7 @@ static void test_exec_environmentfile(Manager *m) {
         int r;
 
         r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
-        assert_se(r == 0);
+        ASSERT_OK(r);
 
         test(m, "exec-environmentfile.service", 0, CLD_EXITED);
 
@@ -1074,19 +1073,19 @@ static void test_exec_passenvironment(Manager *m) {
          * This is still a good approximation of how a test for MANAGER_SYSTEM
          * would work.
          */
-        assert_se(setenv("VAR1", "word1 word2", 1) == 0);
-        assert_se(setenv("VAR2", "word3", 1) == 0);
-        assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
-        assert_se(setenv("VAR4", "new\nline", 1) == 0);
-        assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
+        ASSERT_OK_ERRNO(setenv("VAR1", "word1 word2", 1));
+        ASSERT_OK_ERRNO(setenv("VAR2", "word3", 1));
+        ASSERT_OK_ERRNO(setenv("VAR3", "$word 5 6", 1));
+        ASSERT_OK_ERRNO(setenv("VAR4", "new\nline", 1));
+        ASSERT_OK_ERRNO(setenv("VAR5", "passwordwithbackslashes", 1));
         test(m, "exec-passenvironment.service", 0, CLD_EXITED);
         test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
         test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
-        assert_se(unsetenv("VAR1") == 0);
-        assert_se(unsetenv("VAR2") == 0);
-        assert_se(unsetenv("VAR3") == 0);
-        assert_se(unsetenv("VAR4") == 0);
-        assert_se(unsetenv("VAR5") == 0);
+        ASSERT_OK_ERRNO(unsetenv("VAR1"));
+        ASSERT_OK_ERRNO(unsetenv("VAR2"));
+        ASSERT_OK_ERRNO(unsetenv("VAR3"));
+        ASSERT_OK_ERRNO(unsetenv("VAR4"));
+        ASSERT_OK_ERRNO(unsetenv("VAR5"));
         test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
 }
 
@@ -1368,34 +1367,34 @@ static void run_tests(RuntimeScope scope, char **patterns) {
                 {},
         };
 
-        assert_se(unsetenv("USER") == 0);
-        assert_se(unsetenv("LOGNAME") == 0);
-        assert_se(unsetenv("SHELL") == 0);
-        assert_se(unsetenv("HOME") == 0);
-        assert_se(unsetenv("TMPDIR") == 0);
+        ASSERT_OK_ERRNO(unsetenv("USER"));
+        ASSERT_OK_ERRNO(unsetenv("LOGNAME"));
+        ASSERT_OK_ERRNO(unsetenv("SHELL"));
+        ASSERT_OK_ERRNO(unsetenv("HOME"));
+        ASSERT_OK_ERRNO(unsetenv("TMPDIR"));
 
         /* Unset VARx, especially, VAR1, VAR2 and VAR3, which are used in the PassEnvironment test cases,
          * otherwise (and if they are present in the environment), `manager_default_environment` will copy
          * them into the default environment which is passed to each created job, which will make the tests
          * that expect those not to be present to fail. */
-        assert_se(unsetenv("VAR1") == 0);
-        assert_se(unsetenv("VAR2") == 0);
-        assert_se(unsetenv("VAR3") == 0);
-        assert_se(unsetenv("VAR4") == 0);
-        assert_se(unsetenv("VAR5") == 0);
+        ASSERT_OK_ERRNO(unsetenv("VAR1"));
+        ASSERT_OK_ERRNO(unsetenv("VAR2"));
+        ASSERT_OK_ERRNO(unsetenv("VAR3"));
+        ASSERT_OK_ERRNO(unsetenv("VAR4"));
+        ASSERT_OK_ERRNO(unsetenv("VAR5"));
 
-        assert_se(runtime_dir = setup_fake_runtime_dir());
-        assert_se(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
-        assert_se(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
-        assert_se(set_unit_path(unit_paths) >= 0);
+        ASSERT_NOT_NULL(runtime_dir = setup_fake_runtime_dir());
+        ASSERT_NOT_NULL(user_runtime_unit_dir = path_join(runtime_dir, "systemd/user"));
+        ASSERT_NOT_NULL(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
+        ASSERT_OK(set_unit_path(unit_paths));
 
         r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
         if (manager_errno_skip_test(r))
                 return (void) log_tests_skipped_errno(r, "manager_new");
-        assert_se(r >= 0);
+        ASSERT_OK(r);
 
         m->defaults.std_output = EXEC_OUTPUT_INHERIT; /* don't rely on host journald */
-        assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
+        ASSERT_OK(manager_startup(m, NULL, NULL, NULL));
 
         /* Uncomment below if you want to make debugging logs stored to journal. */
         //manager_override_log_target(m, LOG_TARGET_AUTO);
@@ -1434,64 +1433,66 @@ static int prepare_ns(const char *process_name) {
                       FORK_NEW_MOUNTNS |
                       FORK_MOUNTNS_SLAVE,
                       NULL);
-        assert_se(r >= 0);
+        ASSERT_OK(r);
         if (r == 0) {
                 _cleanup_free_ char *unit_dir = NULL, *build_dir = NULL, *build_dir_mount = NULL;
                 int ret;
 
                 /* Make "/" read-only. */
-                assert_se(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) >= 0);
+                ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL));
 
                 /* Creating a new user namespace in the above means all MS_SHARED mounts become MS_SLAVE.
                  * Let's put them back to MS_SHARED here, since that's what we want as defaults. (This will
                  * not reconnect propagation, but simply create new peer groups for all our mounts). */
-                assert_se(mount_follow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_SHARED|MS_REC, NULL) >= 0);
+                ASSERT_OK(mount_follow_verbose(LOG_DEBUG, NULL, "/", NULL, MS_SHARED|MS_REC, NULL));
 
-                assert_se(mkdir_p(PRIVATE_UNIT_DIR, 0755) >= 0);
-                assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", PRIVATE_UNIT_DIR, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
+                ASSERT_OK(mkdir_p(PRIVATE_UNIT_DIR, 0755));
+                ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", PRIVATE_UNIT_DIR, "tmpfs", MS_NOSUID|MS_NODEV, NULL));
                 /* Mark our test "playground" as MS_SLAVE, so we can MS_MOVE mounts underneath it. */
-                assert_se(mount_nofollow_verbose(LOG_DEBUG, NULL, PRIVATE_UNIT_DIR, NULL, MS_SLAVE, NULL) >= 0);
+                ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, NULL, PRIVATE_UNIT_DIR, NULL, MS_SLAVE, NULL));
 
                 /* Copy unit files to make them accessible even when unprivileged. */
-                assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
-                assert_se(copy_directory_at(AT_FDCWD, unit_dir, AT_FDCWD, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
+                ASSERT_OK(get_testdata_dir("test-execute/", &unit_dir));
+                ASSERT_OK(copy_directory_at(AT_FDCWD, unit_dir, AT_FDCWD, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY));
 
                 /* Mount tmpfs on the following directories to make not StateDirectory= or friends disturb the host. */
                 ret = get_build_exec_dir(&build_dir);
-                assert_se(ret >= 0 || ret == -ENOEXEC);
+                if (ret != -ENOEXEC)
+                        ASSERT_OK(ret);
 
                 if (build_dir) {
                         /* Account for a build directory being in one of the soon-to-be-tmpfs directories. If we
                          * overmount it with an empty tmpfs, manager_new() will pin the wrong systemd-executor binary,
                          * which can then lead to unexpected (and painful to debug) test fails. */
-                        assert_se(access(build_dir, F_OK) >= 0);
-                        assert_se(build_dir_mount = path_join(PRIVATE_UNIT_DIR, "build_dir"));
-                        assert_se(mkdir_p(build_dir_mount, 0755) >= 0);
-                        assert_se(mount_nofollow_verbose(LOG_DEBUG, build_dir, build_dir_mount, NULL, MS_BIND, NULL) >= 0);
+                        ASSERT_OK_ERRNO(access(build_dir, F_OK));
+                        ASSERT_NOT_NULL(build_dir_mount = path_join(PRIVATE_UNIT_DIR, "build_dir"));
+                        ASSERT_OK(mkdir_p(build_dir_mount, 0755));
+                        ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, build_dir, build_dir_mount, NULL, MS_BIND, NULL));
                 }
 
                 FOREACH_STRING(p, "/dev/shm", "/root", "/tmp", "/var/tmp", "/var/lib")
-                        assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL) >= 0);
+                        ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, NULL));
 
                 if (build_dir_mount) {
                         ret = RET_NERRNO(access(build_dir, F_OK));
-                        assert_se(ret >= 0 || ret == -ENOENT);
+                        if (ret != -ENOENT)
+                                ASSERT_OK(ret);
 
                         if (ret == -ENOENT) {
                                 /* The build directory got overmounted by tmpfs, so let's use the "backup" bind mount to
                                  * bring it back. */
-                                assert_se(mkdir_p(build_dir, 0755) >= 0);
-                                assert_se(mount_nofollow_verbose(LOG_DEBUG, build_dir_mount, build_dir, NULL, MS_MOVE, NULL) >= 0);
+                                ASSERT_OK(mkdir_p(build_dir, 0755));
+                                ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, build_dir_mount, build_dir, NULL, MS_MOVE, NULL));
                         }
                 }
 
                 /* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
                 FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
-                        assert_se(mkdir_p(p, 0) >= 0);
-                        assert_se(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, "mode=0000") >= 0);
+                        ASSERT_OK(mkdir_p(p, 0));
+                        ASSERT_OK(mount_nofollow_verbose(LOG_DEBUG, "tmpfs", p, "tmpfs", MS_NOSUID|MS_NODEV, "mode=0000"));
                 }
 
-                assert_se(write_string_file("/run/credstore/test-execute.load-credential", "foo", WRITE_STRING_FILE_CREATE) >= 0);
+                ASSERT_OK(write_string_file("/run/credstore/test-execute.load-credential", "foo", WRITE_STRING_FILE_CREATE));
         }
 
         return r;
@@ -1504,7 +1505,7 @@ TEST(run_tests_root) {
                 return (void) log_tests_skipped("unshare() is disabled");
 
         /* safe_fork() clears saved_argv in the child process. Let's copy it. */
-        assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
+        ASSERT_NOT_NULL(filters = strv_copy(strv_skip(saved_argv, 1)));
 
         if (prepare_ns("(test-execute-root)") == 0) {
                 can_unshare = true;
@@ -1530,19 +1531,18 @@ TEST(run_tests_without_unshare) {
                 return (void) log_tests_skipped("Seccomp not available, cannot run unshare() filtered tests");
 
         /* safe_fork() clears saved_argv in the child process. Let's copy it. */
-        assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
+        ASSERT_NOT_NULL(filters = strv_copy(strv_skip(saved_argv, 1)));
 
         if (prepare_ns("(test-execute-without-unshare)") == 0) {
                 _cleanup_hashmap_free_ Hashmap *s = NULL;
 
                 r = seccomp_syscall_resolve_name("unshare");
-                assert_se(r != __NR_SCMP_ERROR);
-                assert_se(hashmap_ensure_put(&s, NULL, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)) >= 0);
-                assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true) >= 0);
+                ASSERT_NE(r, __NR_SCMP_ERROR);
+                ASSERT_OK(hashmap_ensure_put(&s, NULL, UINT32_TO_PTR(r + 1), INT_TO_PTR(-1)));
+                ASSERT_OK(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EOPNOTSUPP), true));
 
                 /* Check unshare() is actually filtered. */
-                assert_se(unshare(CLONE_NEWNS) < 0);
-                assert_se(errno == EOPNOTSUPP);
+                ASSERT_ERROR_ERRNO(unshare(CLONE_NEWNS), EOPNOTSUPP);
 
                 can_unshare = false;
                 run_tests(RUNTIME_SCOPE_SYSTEM, filters);
@@ -1560,10 +1560,10 @@ TEST(run_tests_unprivileged) {
                 return (void) log_tests_skipped("unshare() is disabled");
 
         /* safe_fork() clears saved_argv in the child process. Let's copy it. */
-        assert_se(filters = strv_copy(strv_skip(saved_argv, 1)));
+        ASSERT_NOT_NULL(filters = strv_copy(strv_skip(saved_argv, 1)));
 
         if (prepare_ns("(test-execute-unprivileged)") == 0) {
-                assert_se(capability_bounding_set_drop(0, /* right_now = */ true) >= 0);
+                ASSERT_OK(capability_bounding_set_drop(0, /* right_now = */ true));
 
                 can_unshare = false;
                 run_tests(RUNTIME_SCOPE_USER, filters);
index 8f00e598fdd676728843bac01c488e1be80a7fa8..cfbd8e270a8792051fc133e9e065cfda00a0a62a 100644 (file)
@@ -116,9 +116,18 @@ TEST(fdset_close_others) {
         copyfd = fdset_put_dup(fdset, fd);
         assert_se(copyfd >= 0);
 
+        /* fdset_close_others() will close any logging file descriptors as well, so close them beforehand
+         * and reopen them again afterwards. */
+        log_close();
         assert_se(fdset_close_others(fdset) >= 0);
+
         flags = fcntl(fd, F_GETFD);
         assert_se(flags < 0);
+
+        /* Open log again after checking that fd is invalid, since reopening the log might make fd a valid
+         * file descriptor again. */
+        (void) log_open();
+
         flags = fcntl(copyfd, F_GETFD);
         assert_se(flags >= 0);
 }
index 3ddbeec0fc78c509cc0f302b8468d33b4ab627d6..48fdbba6c7de971a1919217610d315f6d450ff0f 100644 (file)
@@ -199,7 +199,7 @@ TEST(id128) {
 }
 
 TEST(sd_id128_get_invocation) {
-        sd_id128_t id;
+        sd_id128_t id = SD_ID128_NULL;
         int r;
 
         /* Query the invocation ID */
@@ -208,6 +208,36 @@ TEST(sd_id128_get_invocation) {
                 log_warning_errno(r, "Failed to get invocation ID, ignoring: %m");
         else
                 log_info("Invocation ID: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
+
+        sd_id128_t appid = SD_ID128_NULL;
+        r = sd_id128_get_invocation_app_specific(SD_ID128_MAKE(59,36,e9,92,fd,11,42,fe,87,c9,e9,b5,6c,9e,4f,04), &appid);
+        if (r < 0)
+                log_warning_errno(r, "Failed to get invocation ID, ignoring: %m");
+        else {
+                assert(!sd_id128_equal(id, appid));
+                log_info("Per-App Invocation ID: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(appid));
+        }
+
+        sd_id128_t appid2 = SD_ID128_NULL;
+        r = sd_id128_get_invocation_app_specific(SD_ID128_MAKE(59,36,e9,92,fd,11,42,fe,87,c9,e9,b5,6c,9e,4f,05), &appid2); /* slightly different appid */
+        if (r < 0)
+                log_warning_errno(r, "Failed to get invocation ID, ignoring: %m");
+        else {
+                assert(!sd_id128_equal(id, appid2));
+                assert(!sd_id128_equal(appid, appid2));
+                log_info("Per-App Invocation ID 2: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(appid2));
+        }
+
+        sd_id128_t appid3 = SD_ID128_NULL;
+        r = sd_id128_get_invocation_app_specific(SD_ID128_MAKE(59,36,e9,92,fd,11,42,fe,87,c9,e9,b5,6c,9e,4f,04), &appid3); /* same appid as before */
+        if (r < 0)
+                log_warning_errno(r, "Failed to get invocation ID, ignoring: %m");
+        else {
+                assert(!sd_id128_equal(id, appid3));
+                assert(sd_id128_equal(appid, appid3));
+                assert(!sd_id128_equal(appid2, appid3));
+                log_info("Per-App Invocation ID 3: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(appid3));
+        }
 }
 
 TEST(benchmark_sd_id128_get_machine_app_specific) {
index 05e15c8bdcfae01e54e5433cedaf8ad821829a63..9e2875d8a71ffae55e3df5fc990afea92c5e8b80 100644 (file)
@@ -1,7 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <stddef.h>
+#include <sys/stat.h>
 
+#include "errno-util.h"
 #include "log.h"
 #include "macro.h"
 #include "tests.h"
@@ -1120,6 +1122,19 @@ TEST(ASSERT) {
         ASSERT_SIGNAL(ASSERT_OK_ERRNO(-1), SIGABRT);
         ASSERT_SIGNAL(ASSERT_OK_ERRNO(-ENOANO), SIGABRT);
 
+        ASSERT_ERROR(-ENOENT, ENOENT);
+        ASSERT_ERROR(RET_NERRNO(mkdir("/i/will/fail/with/enoent", 666)), ENOENT);
+        ASSERT_SIGNAL(ASSERT_ERROR(0, ENOENT), SIGABRT);
+        ASSERT_SIGNAL(ASSERT_ERROR(RET_NERRNO(mkdir("/i/will/fail/with/enoent", 666)), ENOANO), SIGABRT);
+
+        errno = ENOENT;
+        ASSERT_ERROR_ERRNO(-1, ENOENT);
+        errno = 0;
+        ASSERT_ERROR_ERRNO(mkdir("/i/will/fail/with/enoent", 666), ENOENT);
+        ASSERT_SIGNAL(ASSERT_ERROR_ERRNO(0, ENOENT), SIGABRT);
+        errno = 0;
+        ASSERT_SIGNAL(ASSERT_ERROR_ERRNO(mkdir("/i/will/fail/with/enoent", 666), ENOANO), SIGABRT);
+
         ASSERT_TRUE(true);
         ASSERT_TRUE(255);
         ASSERT_TRUE(getpid());
index feb16b61a464487aa97150e055340e9d3d9bd3e5..88646ec053eb64cb762138a5faa39ec89315286a 100644 (file)
@@ -47,7 +47,7 @@ TEST(path_pick) {
 
         PickFilter filter = {
                 .architecture = _ARCHITECTURE_INVALID,
-                .suffix = ".raw",
+                .suffix = STRV_MAKE(".raw"),
         };
 
         if (IN_SET(native_architecture(), ARCHITECTURE_X86, ARCHITECTURE_X86_64)) {
index 4840ba47b1c1b386b8623a2ec0e5c19fe79b6e4b..e3b4367ec0536180d4e6dc5920ab62b47e4dc72c 100644 (file)
@@ -596,6 +596,8 @@ static int property_get_rtc_time(
                 log_warning("/dev/rtc is busy. Is somebody keeping it open continuously? That's not a good idea... Returning a bogus RTC timestamp.");
         else if (r == -ENOENT)
                 log_debug("/dev/rtc not found.");
+        else if (r == -ENODATA)
+                log_debug("/dev/rtc has no valid time, power loss probably occurred?");
         else if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %m");
         else
index 686377200f4026a0ea72e5ec1cce4b87e9b41b5f..50d921b7a80e88151d79ae68e4ff90e82273c003 100755 (executable)
@@ -303,6 +303,7 @@ class Uname:
 DEFAULT_SECTIONS_TO_SHOW = {
         '.linux'    : 'binary',
         '.initrd'   : 'binary',
+        '.ucode'    : 'binary',
         '.splash'   : 'binary',
         '.dtb'      : 'binary',
         '.cmdline'  : 'text',
@@ -855,6 +856,7 @@ def make_uki(opts):
         ('.splash',  opts.splash,     True ),
         ('.pcrpkey', pcrpkey,         True ),
         ('.initrd',  initrd,          True ),
+        ('.ucode',   opts.microcode,  True ),
 
         # linux shall be last to leave breathing room for decompression.
         # We'll add it later.
@@ -1279,6 +1281,14 @@ CONFIG_ITEMS = [
         config_push = ConfigItem.config_list_prepend,
     ),
 
+    ConfigItem(
+        '--microcode',
+        metavar = 'UCODE',
+        type = pathlib.Path,
+        help = 'microcode file [.ucode section]',
+        config_key = 'UKI/Microcode',
+    ),
+
     ConfigItem(
         ('--config', '-c'),
         metavar = 'PATH',
index 0eba4569715140e207f4d32e7ad95c87b5243279..9366ce111da4dadc164524e1402a042d4cee96fd 100644 (file)
@@ -1248,7 +1248,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                 log_warning("Couldn't find OVMF firmware blob with Secure Boot support, "
                             "falling back to OVMF firmware blobs without Secure Boot support.");
 
-        shm = arg_directory ? ",memory-backend=mem" : "";
+        shm = arg_directory || arg_runtime_mounts.n_mounts != 0 ? ",memory-backend=mem" : "";
         if (ARCHITECTURE_SUPPORTS_SMM)
                 machine = strjoin("type=" QEMU_MACHINE_TYPE ",smm=", on_off(ovmf_config->supports_sb), shm);
         else
@@ -1294,6 +1294,24 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                 if (strv_extend_many(&cmdline, "-uuid", SD_ID128_TO_UUID_STRING(arg_uuid)) < 0)
                         return log_oom();
 
+        /* Derive a vmgenid automatically from the invocation ID, in a deterministic way. */
+        sd_id128_t vmgenid;
+        r = sd_id128_get_invocation_app_specific(SD_ID128_MAKE(bd,84,6d,e3,e4,7d,4b,6c,a6,85,4a,87,0f,3c,a3,a0), &vmgenid);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to get invocation ID, making up randomized vmgenid: %m");
+
+                r = sd_id128_randomize(&vmgenid);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to make up randomized vmgenid: %m");
+        }
+
+        _cleanup_free_ char *vmgenid_device = NULL;
+        if (asprintf(&vmgenid_device, "vmgenid,guid=" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(vmgenid)) < 0)
+                return log_oom();
+
+        if (strv_extend_many(&cmdline, "-device", vmgenid_device) < 0)
+                return log_oom();
+
         /* if we are going to be starting any units with state then create our runtime dir */
         if (arg_tpm != 0 || arg_directory || arg_runtime_mounts.n_mounts != 0) {
                 r = runtime_directory(&arg_runtime_directory, arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, "systemd/vmspawn");
@@ -1421,7 +1439,13 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                 pass_fds[n_pass_fds++] = device_fd;
         }
 
-        r = strv_extend_many(&cmdline, "-cpu", "max");
+        r = strv_extend_many(&cmdline, "-cpu",
+#ifdef __x86_64__
+                             "max,hv_relaxed,hv-vapic,hv-time"
+#else
+                             "max"
+#endif
+        );
         if (r < 0)
                 return log_oom();
 
@@ -1875,6 +1899,18 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                         return log_error_errno(r, "Failed to call getsockname on VSOCK: %m");
         }
 
+        const char *e = secure_getenv("SYSTEMD_VMSPAWN_QEMU_EXTRA");
+        if (e) {
+                _cleanup_strv_free_ char **extra = NULL;
+
+                r = strv_split_full(&extra, e, /* separator= */ NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to split $SYSTEMD_VMSPAWN_QEMU_EXTRA environment variable: %m");
+
+                if (strv_extend_strv(&cmdline, extra, /* filter_duplicates= */ false) < 0)
+                        return log_oom();
+        }
+
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *joined = quote_command_line(cmdline, SHELL_ESCAPE_EMPTY);
                 if (!joined)
index f3afc33a5897efb74e08c5780c59173ec88abc4b..0504b7733b7e91a9214c844b1dacbb32aca6bf9d 100644 (file)
@@ -241,7 +241,7 @@ static int run(int argc, char *argv[]) {
                                       .basename = arg_filter_basename,
                                       .version = arg_filter_version,
                                       .architecture = arg_filter_architecture,
-                                      .suffix = arg_filter_suffix,
+                                      .suffix = STRV_MAKE(arg_filter_suffix),
                                       .type_mask = arg_filter_type_mask,
                               },
                               arg_flags,
index e14a2613df13a74a6873eefee3948174da27739b..17b45a433914b904b67baf50c52f2d571d9a7fc7 100755 (executable)
@@ -6909,9 +6909,11 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
         check(self, False, False)
 
     def test_dhcp_client_default_use_domains(self):
-        def check(self, ipv4, ipv6):
+        def check(self, common, ipv4, ipv6):
             mkdir_p(networkd_conf_dropin_dir)
             with open(os.path.join(networkd_conf_dropin_dir, 'default_use_domains.conf'), mode='w', encoding='utf-8') as f:
+                f.write('[Network]\nUseDomains=')
+                f.write('yes\n' if common else 'no\n')
                 f.write('[DHCPv4]\nUseDomains=')
                 f.write('yes\n' if ipv4 else 'no\n')
                 f.write('[DHCPv6]\nUseDomains=')
@@ -6932,7 +6934,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
 
             for _ in range(20):
                 output = resolvectl('domain', 'veth99')
-                if ipv4 or ipv6:
+                if common or ipv4 or ipv6:
                     if 'example.com' in output:
                         break
                 else:
@@ -6941,16 +6943,18 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
                 time.sleep(0.5)
             else:
                 print(output)
+                print(read_link_state_file('veth99'))
                 self.fail('unexpected domain setting in resolved...')
 
             stop_dnsmasq()
             remove_networkd_conf_dropin('default_use_domains.conf')
 
         copy_network_unit('25-veth.netdev', '25-dhcp-server-veth-peer.network', '25-dhcp-client.network', copy_dropins=False)
-        check(self, True, True)
-        check(self, True, False)
-        check(self, False, True)
-        check(self, False, False)
+        check(self, True, False, False)
+        check(self, False, True, True)
+        check(self, False, True, False)
+        check(self, False, False, True)
+        check(self, False, False, False)
 
     def test_dhcp_client_use_captive_portal(self):
         def check(self, ipv4, ipv6):
index 977d76e22f0955e481d5c848c90810f05d5c85a2..4c0f1ba3293cf8770284534465e6bd1e0ba34fcc 100755 (executable)
@@ -183,6 +183,26 @@ status="$(portablectl is-attached --extension app1 minimal_0)"
 
 portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1
 
+# Ensure vpick works, including reattaching to a new image
+mkdir -p /tmp/app1.v/
+cp /usr/share/app1.raw /tmp/app1.v/app1_1.0.raw
+cp /tmp/app1_2.raw /tmp/app1.v/app1_2.0.raw
+portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
+
+systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1_2.0.raw minimal_1)"
+[[ "${status}" == "running-runtime" ]]
+
+rm -f /tmp/app1.v/app1_2.0.raw
+portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1
+
+systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1_1.0.raw minimal_1)"
+[[ "${status}" == "running-runtime" ]]
+
+portablectl detach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_0.raw app1
+rm -f /tmp/app1.v/app1_1.0.raw
+
 # Ensure that the combination of read-only images, state directory and dynamic user works, and that
 # state is retained. Check after detaching, as on slow systems (eg: sanitizers) it might take a while
 # after the service is attached before the file appears.