]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #27946 from keszybz/ukify-genkey-verb
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 14 Jun 2023 15:57:24 +0000 (17:57 +0200)
committerGitHub <noreply@github.com>
Wed, 14 Jun 2023 15:57:24 +0000 (17:57 +0200)
Add 'genkey' verb to ukify

273 files changed:
.github/workflows/mkosi.yml
.github/workflows/scorecards.yml
TODO
catalog/systemd.catalog.in
docs/CONTAINER_INTERFACE.md
docs/CREDENTIALS.md
hwdb.d/60-keyboard.hwdb
man/bootctl.xml
man/integritytab.xml
man/journalctl.xml
man/journald.conf.xml
man/kernel-command-line.xml
man/kernel-install.xml
man/meson.build
man/org.freedesktop.portable1.xml
man/org.freedesktop.resolve1.xml
man/org.freedesktop.systemd1.xml
man/os-release.xml
man/resolvectl.xml
man/sd-event.xml
man/sd_bus_get_fd.xml
man/sd_bus_wait.xml
man/sd_event_add_time.xml
man/sd_event_now.xml
man/sd_login_monitor_new.xml
man/sd_notify.xml
man/sd_session_is_active.xml
man/sd_watchdog_enabled.xml
man/standard-options.xml
man/systemctl.xml
man/systemd-ask-password.xml
man/systemd-coredump.xml
man/systemd-creds.xml
man/systemd-firstboot.xml
man/systemd-repart.xml
man/systemd-resolved.service.xml
man/systemd-sysctl.service.xml
man/systemd-sysusers.xml
man/systemd-timesyncd.service.xml
man/systemd-tmpfiles.xml
man/systemd-vconsole-setup.service.xml
man/systemd.exec.xml
man/systemd.link.xml
man/systemd.resource-control.xml
man/systemd.service.xml
man/systemd.socket.xml
man/systemd.time.xml
man/systemd.timer.xml
man/systemd.unit.xml
man/systemd.xml
man/sysupdate.d.xml
meson.build
mkosi.conf.d/05-qemu-mem.conf
mkosi.conf.d/11-centos-8/mkosi.conf
mkosi.kernel.config
mkosi.presets/00-base/mkosi.conf.d/10-centos-fedora.conf
mkosi.presets/00-base/mkosi.conf.d/10-debian-ubuntu.conf
mkosi.presets/10-initrd/mkosi.conf
mkosi.presets/10-initrd/mkosi.conf.d/10-default.conf
mkosi.presets/20-final/mkosi.conf
mkosi.presets/20-final/mkosi.conf.d/10-arch.conf
mkosi.presets/20-final/mkosi.conf.d/10-centos-fedora.conf
mkosi.presets/20-final/mkosi.conf.d/10-debian-ubuntu.conf
mkosi.presets/20-final/mkosi.conf.d/10-debian.conf
mkosi.presets/20-final/mkosi.conf.d/10-opensuse.conf
mkosi.presets/20-final/mkosi.conf.d/10-ubuntu.conf
mkosi.presets/20-final/mkosi.conf.d/20-kernel-centos-fedora.conf
mkosi.presets/20-final/mkosi.conf.d/20-kernel-debian-ubuntu.conf
mkosi.presets/20-final/mkosi.extra/usr/lib/systemd/mkosi-check-and-shutdown.sh
po/it.po
po/ko.po
presets/90-systemd.preset
rules.d/99-systemd.rules.in
shell-completion/bash/meson.build
shell-completion/zsh/_localectl
src/ac-power/ac-power.c
src/ask-password/ask-password.c
src/basic/chase.c
src/basic/chase.h
src/basic/chattr-util.c
src/basic/chattr-util.h
src/basic/coverage.h
src/basic/fd-util.c
src/basic/fd-util.h
src/basic/fs-util.c
src/basic/meson.build
src/basic/proc-cmdline.c
src/basic/procfs-util.c
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/time-util.c
src/basic/tmpfile-util.c
src/basic/tmpfile-util.h
src/basic/uid-alloc-range.c [moved from src/shared/uid-alloc-range.c with 94% similarity]
src/basic/uid-alloc-range.h [moved from src/shared/uid-alloc-range.h with 95% similarity]
src/boot/bootctl-install.c
src/boot/bootctl.c
src/boot/efi/boot.c
src/boot/efi/initrd.c
src/boot/efi/stub.c
src/boot/pcrphase.c
src/cgls/cgls.c
src/cgtop/cgtop.c
src/core/cgroup.c
src/core/dbus-cgroup.c
src/core/dbus-execute.c
src/core/dbus-job.c
src/core/dbus-unit.c
src/core/dbus.c
src/core/execute.c
src/core/execute.h
src/core/job.c
src/core/load-fragment-gperf.gperf.in
src/core/load-fragment.c
src/core/load-fragment.h
src/core/meson.build
src/core/socket.c
src/core/unit.c
src/coredump/coredump.c
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup.c
src/dissect/dissect.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hibernate-resume/hibernate-resume-generator.c
src/home/homework-luks.c
src/home/pam_systemd_home.c
src/import/export-tar.c
src/import/import-fs.c
src/import/pull-tar.c
src/integritysetup/integrity-util.c
src/integritysetup/integritysetup-generator.c
src/journal-remote/journal-remote-main.c
src/journal-remote/journal-remote.c
src/journal-remote/microhttpd-util.h
src/journal/journald-server.c
src/journal/journald-stream.c
src/kernel-install/kernel-install.c [new file with mode: 0644]
src/kernel-install/kernel-install.in [deleted file]
src/kernel-install/meson.build
src/kernel-install/test-kernel-install.sh
src/libsystemd/libsystemd.sym
src/libsystemd/sd-bus/test-bus-watch-bind.c
src/libsystemd/sd-daemon/sd-daemon.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-journal/sd-journal.c
src/libsystemd/sd-login/sd-login.c
src/libsystemd/sd-netlink/sd-netlink.c
src/libsystemd/sd-netlink/test-netlink.c
src/locale/kbd-model-map
src/login/logind-dbus.c
src/login/systemd-user.in
src/nspawn/nspawn.c
src/partition/repart.c
src/portable/portable.c
src/resolve/resolvectl.c
src/resolve/resolved-bus.c
src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-cache.h
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-stub.c
src/resolve/resolved-link-bus.c
src/resolve/resolved-llmnr.c
src/resolve/resolved-varlink.c
src/shared/battery-util.c
src/shared/btrfs-util.c
src/shared/btrfs-util.h
src/shared/bus-unit-util.c
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/calendarspec.c
src/shared/copy.c
src/shared/copy.h
src/shared/discover-image.c
src/shared/efi-loader.c
src/shared/ethtool-link-mode.py [new file with mode: 0644]
src/shared/ethtool-util.c
src/shared/ethtool-util.h
src/shared/generator.c
src/shared/hwdb-util.c
src/shared/json.c
src/shared/json.h
src/shared/meson.build
src/shared/rm-rf.c
src/shared/rm-rf.h
src/shared/serialize.c
src/shared/serialize.h
src/shared/sleep-config.c
src/shared/socket-netlink.c
src/shared/tpm2-util.c
src/shared/tpm2-util.h
src/shared/varlink.c
src/systemd/sd-daemon.h
src/systemd/sd-login.h
src/test/meson.build
src/test/test-btrfs.c
src/test/test-chase.c
src/test/test-env-file.c
src/test/test-execute.c
src/test/test-id128.c
src/test/test-path-util.c
src/test/test-process-util.c
src/test/test-serialize.c
src/test/test-socket-util.c
src/test/test-time-util.c
src/test/test-tmpfile-util.c
src/test/test-tpm2.c
src/timesync/timesyncd-manager.c
src/timesync/timesyncd.c
src/tmpfiles/tmpfiles.c
src/udev/meson.build
src/udev/udev-node.c
src/udev/udevadm-control.c
src/userdb/userdbd-manager.c
src/xdg-autostart-generator/xdg-autostart-service.c
test/TEST-02-UNITTESTS/deny-list-ubuntu-ci-ppc64el [deleted file]
test/TEST-02-UNITTESTS/test.sh
test/TEST-06-SELINUX/test.sh
test/TEST-16-EXTEND-TIMEOUT/test.sh
test/TEST-21-DFUZZER/test.sh
test/TEST-24-CRYPTSETUP/test.sh
test/TEST-43-PRIVATEUSER-UNPRIV/test.sh
test/TEST-46-HOMED/test.sh
test/TEST-50-DISSECT/test.sh
test/TEST-58-REPART/test.sh
test/TEST-61-UNITTESTS-QEMU/Makefile [deleted symlink]
test/TEST-61-UNITTESTS-QEMU/deny-list-ubuntu-ci [deleted file]
test/TEST-61-UNITTESTS-QEMU/test.sh [deleted file]
test/TEST-70-TPM2/test.sh
test/TEST-75-RESOLVED/test.sh
test/hwdb-test.sh
test/test-execute/exec-dynamicuser-statedir.service
test/test-fstab-generator/test-12-dev-sdx.expected/systemd-fsck-root.service
test/test-fstab-generator/test-13-label.expected/systemd-fsck-root.service
test/test-fstab-generator/test-14-uuid.expected/systemd-fsck-root.service
test/test-fstab-generator/test-15-partuuid.expected/systemd-fsck-root.service
test/test-fstab-generator/test-17-initrd-sysroot.fstab.expected/systemd-fsck-root.service
test/test-fstab-generator/test-18-options.fstab.expected/systemd-fsck-root.service
test/test-fstab-generator/test-18-options.fstab.expected/systemd-makefs@dev-sdx12.service
test/test-fstab-generator/test-20-swap-from-cmdline.expected/systemd-mkswap@dev-sdy2.service
test/test-fstab-generator/test-20-swap-from-cmdline.expected/systemd-mkswap@dev-sdy3.service
test/test-functions
test/test-sysusers.sh.in
test/testsuite-06.units/load-systemd-test-module.service [deleted file]
test/units/autorelabel.service
test/units/testsuite-02.sh
test/units/testsuite-06.service
test/units/testsuite-24.service
test/units/testsuite-24.sh [new file with mode: 0755]
test/units/testsuite-54.sh
test/units/testsuite-58.sh
test/units/testsuite-61.service [deleted file]
test/units/testsuite-61.sh [deleted file]
tools/xml_helper.py
units/rc-local.service.in
units/systemd-firstboot.service
units/systemd-fsck-root.service.in
units/systemd-fsck@.service.in
units/systemd-growfs-root.service.in
units/systemd-growfs@.service.in
units/systemd-quotacheck.service.in
units/systemd-resolved.service.in
units/systemd-sysctl.service.in
units/systemd-sysusers.service
units/systemd-tmpfiles-clean.service
units/systemd-tmpfiles-setup-dev.service
units/systemd-tmpfiles-setup.service
units/systemd-vconsole-setup.service.in

index 9010b1fcb7b97d9bf0fbf5bd7df8fc9768bc3d8b..2b5f204f7a6340758272e477dbd8cbf35baac277 100644 (file)
@@ -76,7 +76,7 @@ jobs:
 
     steps:
     - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
-    - uses: systemd/mkosi@e59f763872e4d5f96acb11b4a77995b986bb31cc
+    - uses: systemd/mkosi@87a6b70ea9ab529b95fc91306fc8151175999dca
 
     - name: Configure
       run: |
@@ -121,11 +121,7 @@ jobs:
       run: mkosi --debug
 
     - name: Boot ${{ matrix.distro }} systemd-nspawn
-      run: sudo mkosi --debug boot
+      run: test "$(sudo mkosi --debug boot 1>&2; echo $?)" -eq 123
 
     - name: Boot ${{ matrix.distro }} QEMU
-      run: timeout -k 30 10m mkosi --debug qemu
-
-    # vsock in Github Actions with qemu is broken so for now we check for failures manually.
-    - name: Check ${{ matrix.distro }} QEMU
-      run: sudo mkosi shell bash -c "[[ -e /testok ]] || { cat /failed-services; exit 1; }"
+      run: timeout -k 30 10m test "$(mkosi --debug qemu 1>&2; echo $?)" -eq 123
index e711f962b446833d4d3935252b4d27e95c664146..2eede1dd8dbb9549be7a31010381ef598af1812e 100644 (file)
@@ -32,12 +32,12 @@ jobs:
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # tag=v3.0.0
+        uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
         with:
           persist-credentials: false
 
       - name: Run analysis
-        uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af # tag=v2.1.3
+        uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af # v2.1.3
         with:
           results_file: results.sarif
           results_format: sarif
@@ -56,7 +56,7 @@ jobs:
       # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
       # format to the repository Actions tab.
       - name: Upload artifact
-        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # tag=v3.0.0
+        uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
         with:
           name: SARIF file
           path: results.sarif
@@ -65,6 +65,6 @@ jobs:
       # Upload the results to GitHub's code scanning dashboard.
       - name: Upload to code-scanning
         if: github.event_name != 'pull_request'
-        uses: github/codeql-action/upload-sarif@0225834cc549ee0ca93cb085b92954821a145866 # tag=v1.0.26
+        uses: github/codeql-action/upload-sarif@0225834cc549ee0ca93cb085b92954821a145866 # v2.20.0
         with:
           sarif_file: results.sarif
diff --git a/TODO b/TODO
index 4c32a4a4caa10b4c286299283fb519f8a5fae76a..d47d860a57123564784450fa2037ff756ba22554 100644 (file)
--- a/TODO
+++ b/TODO
@@ -129,6 +129,19 @@ Deprecations and removals:
 
 Features:
 
+* in sd-stub: optionally add support for a new PE section .keyring or so that
+  contains additional certificates to include in the Mok keyring, extending
+  what shim might have placed there. why? let's say I use "ukify" to build +
+  sign my own fedora-based UKIs, and only enroll my personal lennart key via
+  shim.  Then, I want to include the fedora keyring in it, so that kmods work.
+  But I might not want to enroll the fedora key in shim, because this would
+  also mean that the key would be in effect whenever I boot an archlinux UKI
+  built the same way, signed with the same lennart key.
+
+* resolved: take possession of some IPv6 ULA address (let's say
+  fd00:5353:5353:5353:5353:5353:5353:5353), and listen on port 53 on it for the
+  local stubs, so that we can make the stub available via ipv6 too.
+
 * introduce a .microcode PE section for sd-stub which we'll pass as first initrd
   to the kernel which will then upload it to the CPU. This should be distinct
   from .initrd to guarantee right ordering. also, and maybe more importantly
index d3d03dafe7162767e5f3efed81cdb7f41d5efd35..913d4987ac712bc7aa6a51a3d920c9f887c7ab3c 100644 (file)
@@ -563,4 +563,4 @@ resources back to the OS kernel, making them available for other components of
 the OS.
 
 @TRIMMED_BYTES@ of memory were returned to the OS, which took @TRIMMED_USEC@
-micro-seconds (µs).
+micro-seconds (μs).
index ddeaf8ea4fa09df4b25d16501a0e74eec81606bd..2435d4ae97c6728cff1a0b7eb6f69ed37acb7db4 100644 (file)
@@ -138,15 +138,16 @@ manager, please consider supporting the following interfaces.
    `$container_host_version_id=10`
 
 5. systemd supports passing immutable binary data blobs with limited size and
-   restricted access to services via the `LoadCredential=` and `SetCredential=`
-   settings. The same protocol may be used to pass credentials from the
-   container manager to systemd itself. The credential data should be placed in
-   some location (ideally a read-only and non-swappable file system, like
-   'ramfs'), and the absolute path to this directory exported in the
+   restricted access to services via the `ImportCredential=`, `LoadCredential=`
+   and `SetCredential=` settings. The same protocol may be used to pass credentials
+   from the container manager to systemd itself. The credential data should be
+   placed in some location (ideally a read-only and non-swappable file system,
+   like 'ramfs'), and the absolute path to this directory exported in the
    `$CREDENTIALS_DIRECTORY` environment variable. If the container managers
    does this, the credentials passed to the service manager can be propagated
-   to services via `LoadCredential=` (see ...). The container manager can
-   choose any path, but `/run/host/credentials` is recommended.
+   to services via `LoadCredential=` or `ImportCredential=` (see ...). The
+   container manager can choose any path, but `/run/host/credentials` is
+   recommended.
 
 ## Advanced Integration
 
index 083c7ecc3c532409622b15128e64cf00827dc604..2f6bdd44b2e936320b903671538565c611fc7723 100644 (file)
@@ -72,6 +72,9 @@ Within unit files, there are four settings to configure service credentials.
 1. `LoadCredential=` may be used to load a credential from disk, from an
    `AF_UNIX` socket, or propagate them from a system credential.
 
+2. `ImportCredential=` may be used to load one or more (encrypted) credentials
+   from disk or from the credential stores.
+
 2. `SetCredential=` may be used to set a credential to a literal string encoded
    in the unit file. Because unit files are world-readable (both on disk and
    via D-Bus), this should only be used for credentials that aren't sensitive,
@@ -323,7 +326,7 @@ systemd-creds --system cat mycred
 Or propagated to services further down:
 
 ```
-systemd-run -p LoadCredential=mycred -P --wait systemd-creds cat mycred
+systemd-run -p ImportCredential=mycred -P --wait systemd-creds cat mycred
 ```
 
 ## Well-Known Credentials
@@ -430,13 +433,14 @@ a container manager or via qemu) and `/run/credentials/@encrypted/` (for
 credentials that must be decrypted/validated before use, such as those from
 `systemd-stub`).
 
-The `LoadCredential=` and `LoadCredentialEncrypted=` settings when configured
-with a relative source path will search for the source file to read the
-credential from automatically. Primarily, these credentials are searched among
-the credentials passed into the system. If not found there, they are searched
-in `/etc/credstore/`, `/run/credstore/`,
+The `ImportCredential=` setting (and the `LoadCredential=` and
+`LoadCredentialEncrypted=` settings when configured with a relative source path)
+will search for the source file to read the credential from automatically. Primarily,
+these credentials are searched among the credentials passed into the system. If
+not found there, they are searched in `/etc/credstore/`, `/run/credstore/`,
 `/usr/lib/credstore/`. `LoadCredentialEncrypted=` will also search
-`/etc/credstore.encrypted/` and similar directories. These directories are
+`/etc/credstore.encrypted/` and similar directories. `ImportCredential` will search
+both the non-encrypted and encrypted directories. These directories are
 hence a great place to store credentials to load on the system.
 
 ## Conditionalizing Services
index 27113276c47f2c3856ff3b724ab3e59705ad5a7c..492092e685c4d6503e402e0ab7ebfadaca6c70ed 100644 (file)
@@ -827,6 +827,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteDragonflyG2*:pvr*
 evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pnHPEliteDragonflyG2*:pvr*
  KEYBOARD_KEY_08=unknown                                # rfkill is also reported by HP Wireless hotkeys
 
+# HP Elite Dragonfly G3
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteDragonfly13.5inchG3NotebookPC:pvr*
+ KEYBOARD_KEY_c9=up
+ KEYBOARD_KEY_d1=down
+ KEYBOARD_KEY_c8=pageup
+ KEYBOARD_KEY_d0=pagedown
+
 ##########################################################
 # Huawei
 ##########################################################
index 5f98486343d813539f44901a940c679ed4fefd48..3219ae247b3e2bf3a6b8694c63a22b56a3db8779 100644 (file)
       <varlistentry>
         <term><option>random-seed</option></term>
 
-        <listitem><para>Generates a random seed and stores it in the EFI System Partition, for use by the
-        <command>systemd-boot</command> boot loader. Also, generates a random 'system token' and stores it
-        persistently as an EFI variable, if one has not been set before. If the boot loader finds the random
-        seed in the ESP and the system token in the EFI variable it will derive a random seed to pass to the
-        OS and a new seed to store in the ESP from the combination of both. The random seed passed to the OS
-        is credited to the kernel's entropy pool by the system manager during early boot, and permits
-        userspace to boot up with an entropy pool fully initialized very early on. Also see
+        <listitem><para>Generates a random seed and stores it in the EFI System Partition (ESP), for use by
+        the <command>systemd-boot</command> boot loader. If a random seed already exists in the ESP it is
+        refreshed. Also generates a random 'system token' and stores it persistently as an EFI variable, if
+        one has not been set before. If the boot loader finds the random seed in the ESP and the system token
+        in the EFI variable it will derive a random seed to pass to the OS and a new seed to store in the ESP
+        from the combination of both. The random seed passed to the OS is credited to the kernel's entropy
+        pool by the system manager during early boot, and permits userspace to boot up with an entropy pool
+        fully initialized very early on. Also see
         <citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
 
         <para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for further
     <para>The following options are understood:</para>
 
     <variablelist>
-      <varlistentry>
-        <term><option>--esp-path=</option></term>
-        <listitem><para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi/</filename>,
-        <filename>/boot/</filename>, and <filename>/boot/efi/</filename> are checked in turn.  It is
-        recommended to mount the ESP to <filename>/efi/</filename>, if possible.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--boot-path=</option></term>
-        <listitem><para>Path to the Extended Boot Loader partition, as defined in the <ulink
-        url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>. If not
-        specified, <filename>/boot/</filename> is checked.  It is recommended to mount the Extended Boot
-        Loader partition to <filename>/boot/</filename>, if possible.</para></listitem>
-      </varlistentry>
+      <xi:include href="standard-options.xml" xpointer="esp-path"/>
+      <xi:include href="standard-options.xml" xpointer="boot-path"/>
 
       <varlistentry>
         <term><option>--root=<replaceable>root</replaceable></option></term>
index 44da039ddecf9dce658a9d5c8ec9612b5e2c00a1..12ec2933a9d595ee7eb650cb8931e5d1674bf4b9 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><option>no-journal</option></term>
+        <term><option>mode=(journal|bitmap|direct)</option></term>
 
         <listitem><para>
-        Disable the journal. Corresponds to the "direct writes" mode documented in
+        Enable journaled, bitmapped or direct (passthrough) mode. Journaled mode is the default when this option is not specified.
+        It provides safety against crashes, but can be slow because all data has to be written twice.
+        Bitmap mode is more efficient since it requires only a single write, but it is less reliable because if data corruption happens when the machine crashes, it may not be detected.
+        Direct mode disables the journal and the bitmap. Corresponds to the "direct writes" mode documented in
         <ulink url="https://docs.kernel.org/admin-guide/device-mapper/dm-integrity.html">the dm-integrity documentation</ulink>.
         Note that without a journal, if there is a crash, it is possible that the integrity tags and data will not match. If used, the journal-*
         options below will have no effect if passed.
index aa124dd98f06c63112aac73e1be9f602c29352e2..d54937a220422a3f2654527da32c52c6076215d0 100644 (file)
         <option>--user</option>).  If neither is specified, show all messages that the user can see.
         </para>
 
-        <para>The <option>--user</option> option affects how <option>--unit</option> arguments are
-        treated. See <option>--unit</option>.</para></listitem>
+        <para>The <option>--user</option> option affects how <option>--unit=</option> arguments are
+        treated. See <option>--unit=</option>.</para>
+
+        <para>Note that <option>--user</option> only works if persistent logging is enabled, via the
+        <varname>Storage=</varname> setting in
+        <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         unit, all logs of children of the slice will be shown.</para>
 
-        <para>With <option>--user</option>, all <option>--unit</option> arguments will be converted to match
-        user messages as if specified with <option>--user-unit</option>.</para>
+        <para>With <option>--user</option>, all <option>--unit=</option> arguments will be converted to match
+        user messages as if specified with <option>--user-unit=</option>.</para>
 
         <para>This parameter can be specified multiple times.</para></listitem>
       </varlistentry>
         <term><option>--vacuum-time=</option></term>
         <term><option>--vacuum-files=</option></term>
 
-        <listitem><para>Removes the oldest archived journal files until the disk space they use falls below
-        the specified size (specified with the usual <literal>K</literal>, <literal>M</literal>,
-        <literal>G</literal> and <literal>T</literal> suffixes), or all archived journal files contain no
-        data older than the specified timespan (specified with the usual <literal>s</literal>,
-        <literal>m</literal>, <literal>h</literal>, <literal>days</literal>, <literal>months</literal>,
-        <literal>weeks</literal> and <literal>years</literal> suffixes), or no more than the specified
-        number of separate journal files remain. Note that running <option>--vacuum-size=</option> has only
-        an indirect effect on the output shown by <option>--disk-usage</option>, as the latter includes
-        active journal files, while the vacuuming operation only operates on archived journal
-        files. Similarly, <option>--vacuum-files=</option> might not actually reduce the number of journal
-        files to below the specified number, as it will not remove active journal files.</para>
+        <listitem><para><option>--vacuum-size=</option> removes the oldest archived journal files until the
+        disk space they use falls below the specified size. Accepts the usual <literal>K</literal>,
+        <literal>M</literal>, <literal>G</literal> and <literal>T</literal> suffixes (to the base of
+        1024).</para>
+
+        <para><option>--vacuum-time=</option> removes archived journal files older than the specified
+        timespan. Accepts the usual <literal>s</literal> (default), <literal>m</literal>,
+        <literal>h</literal>, <literal>days</literal>, <literal>months</literal>, <literal>weeks</literal>
+        and <literal>years</literal> suffixes, see
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details.</para>
+
+        <para><option>--vacuum-files=</option> leaves only the specified number of separate journal
+        files.</para>
+
+        <para>Note that running <option>--vacuum-size=</option> has only an indirect effect on the output
+        shown by <option>--disk-usage</option>, as the latter includes active journal files, while the
+        vacuuming operation only operates on archived journal files. Similarly,
+        <option>--vacuum-files=</option> might not actually reduce the number of journal files to below the
+        specified number, as it will not remove active journal files.</para>
 
         <para><option>--vacuum-size=</option>, <option>--vacuum-time=</option> and
-        <option>--vacuum-files=</option> may be combined in a single invocation to enforce any combination
-        of a size, a time and a number of files limit on the archived journal files. Specifying any of
-        these three parameters as zero is equivalent to not enforcing the specific limit, and is thus
+        <option>--vacuum-files=</option> may be combined in a single invocation to enforce any combination of
+        a size, a time and a number of files limit on the archived journal files. Specifying any of these
+        three parameters as zero is equivalent to not enforcing the specific limit, and is thus
         redundant.</para>
 
         <para>These three switches may also be combined with <option>--rotate</option> into one command. If
index 50c33e479294b1357acae730554c13aa67feef40..2642872407a13d77e0df521394a7ee04bf7583b0 100644 (file)
@@ -95,6 +95,9 @@
         <filename>/var/log/journal/</filename>, as the <filename>systemd-journald@.service</filename> service
         file by default carries <varname>LogsDirectory=</varname>. To turn that off, add a unit file drop-in
         file that sets <varname>LogsDirectory=</varname> to an empty string.</para>
+
+        <para>Note that per-user journal files are not supported unless persistent storage is enabled, thus
+        making <command>journalctl --user</command> unavailable.</para>
         </listitem>
       </varlistentry>
 
index 479b482a308b4f91e004e660f888172ef4ff432c..eef6db4a5c5a4456040838e7701b6b0a17e87942 100644 (file)
       <varlistentry>
         <term><varname>systemd.clock-usec=</varname></term>
 
-        <listitem><para>Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the
+        <listitem><para>Takes a decimal, numeric timestamp in μs since January 1st 1970, 00:00am, to set the
         system clock to. The system time is set to the specified timestamp early during boot. It is not
         propagated to the hardware clock (RTC).</para></listitem>
       </varlistentry>
index 4f71d67e2f0666703a6e72441e27bc3d411111dd..b3aed1b8df07c0f39a5365a3f76c9f1088612f9d 100644 (file)
@@ -40,6 +40,7 @@
       <command>kernel-install</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
       <arg choice="plain">inspect</arg>
+      <arg choice="opt"><replaceable>KERNEL-IMAGE</replaceable></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
         </listitem>
       </varlistentry>
       <varlistentry>
-        <term><command>inspect</command></term>
+        <term><command>inspect [<replaceable>KERNEL-IMAGE</replaceable>]</command></term>
         <listitem>
           <para>Shows the various paths and parameters configured or auto-detected. In particular shows the
           values of the various <varname>$KERNEL_INSTALL_*</varname> environment variables listed
     <para>The following options are understood:</para>
 
     <variablelist>
+      <xi:include href="standard-options.xml" xpointer="esp-path"/>
+      <xi:include href="standard-options.xml" xpointer="boot-path"/>
+
+      <varlistentry>
+        <term><option>--make-entry-directory=yes|no|auto</option></term>
+        <listitem>
+          <para>Controls creation and deletion of the
+          <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>
+          Type #1 entry directory on the file system containing resources such as kernel and initrd images
+          during <option>add</option> and <option>remove</option>, respectively. The directory is named after
+          the entry token, and is placed immediately below the boot root directory. When
+          <literal>auto</literal>, the directory is created or removed only when the install layout is
+          <literal>bls</literal>. Defaults to <literal>auto</literal>.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--entry-token=</option></term>
+
+        <listitem>
+          <para>Controls how to name and identify boot loader entries for this kernel installation or
+          deletion. Takes one of <literal>auto</literal>, <literal>machine-id</literal>,
+          <literal>os-id</literal>, <literal>os-image-id</literal>, or an arbitrary string prefixed by
+          <literal>literal:</literal> as argument.</para>
+
+          <para>If set to <option>machine-id</option> the entries are named after the machine ID of the
+          running system (e.g. <literal>b0e793a9baf14b5fa13ecbe84ff637ac</literal>). See
+          <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+          details about the machine ID concept and file.</para>
+
+          <para>If set to <option>os-id</option> the entries are named after the OS ID of the running system,
+          i.e. the <varname>ID=</varname> field of
+          <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+          (e.g. <literal>fedora</literal>). Similarly, if set to <option>os-image-id</option> the entries are
+          named after the OS image ID of the running system, i.e. the <varname>IMAGE_ID=</varname> field of
+          <filename>os-release</filename> (e.g. <literal>vendorx-cashier-system</literal>).</para>
+
+          <para>If set to <option>auto</option> (the default), the
+          <filename>/etc/kernel/entry-token</filename> (or
+          <filename>$KERNEL_INSTALL_CONF_ROOT/entry-token</filename>) file will be read if it exists, and the
+          stored value used. Otherwise if the local machine ID is initialized it is used. Otherwise
+          <varname>IMAGE_ID=</varname> from <filename>os-release</filename> will be used, if set. Otherwise,
+          <varname>ID=</varname> from <filename>os-release</filename> will be used, if set. Otherwise a
+          randomly generated machine ID is used.</para>
+
+          <para>Using the machine ID for naming the entries is generally preferable, however there are cases
+          where using the other identifiers is a good option. Specifically: if the identification data that
+          the machine ID entails shall not be stored on the (unencrypted) <varname>$BOOT_ROOT</varname>
+          partition, or if the ID shall be generated on first boot and is not known when the entries are
+          prepared. Note that using the machine ID has the benefit that multiple parallel installations of
+          the same OS can coexist on the same medium, and they can update their boot loader entries
+          independently. When using another identifier (such as the OS ID or the OS image ID), parallel
+          installations of the same OS would try to use the same entry name. To support parallel
+          installations, the installer must use a different entry token when adding a second installation.
+          </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>-v</option></term>
         <term><option>--verbose</option></term>
index e6724a53f4a555482f54f447b886d723f6573e2e..4dc5fabd6dee735c42f3073d4b2819b4badc656a 100644 (file)
@@ -20,7 +20,9 @@ xsltproc_flags = [
         '--stringparam', 'man.copyright.section.enabled', '0',
         '--stringparam', 'systemd.version', '@0@'.format(meson.project_version()),
         '--path',
-        '@0@:@1@'.format(meson.current_build_dir(), meson.current_source_dir())]
+        '@0@:@1@:@2@'.format(meson.current_build_dir(),
+                             meson.current_source_dir(),
+                             libshared_build_dir)]
 
 custom_man_xsl = files('custom-man.xsl')
 custom_html_xsl = files('custom-html.xsl')
@@ -32,6 +34,8 @@ custom_entities_ent = custom_target(
         output : 'custom-entities.ent',
         command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'])
 
+man_page_depends += custom_entities_ent
+
 man_pages = []
 html_pages = []
 source_xml_files = []
@@ -68,7 +72,7 @@ foreach tuple : manpages
                                 input : xml,
                                 output : [man] + manaliases,
                                 command : xslt_cmd + [custom_man_xsl, '@INPUT@'],
-                                depends : custom_entities_ent,
+                                depends : man_page_depends,
                                 install : want_man,
                                 install_dir : mandirn)
                         man_pages += p1
@@ -93,7 +97,7 @@ foreach tuple : manpages
                                 input : xml,
                                 output : html,
                                 command : xslt_cmd + [custom_html_xsl, '@INPUT@'],
-                                depends : [custom_entities_ent, p2],
+                                depends : [man_page_depends, p2],
                                 install : want_html,
                                 install_dir : docdir / 'html')
                         html_pages += p3
@@ -114,7 +118,7 @@ systemd_directives_xml = custom_target(
         'systemd.directives.xml',
         input : ['directives-template.xml', source_xml_files],
         output : 'systemd.directives.xml',
-        depends : custom_entities_ent,
+        depends : man_page_depends,
         command : [make_directive_index_py, '@OUTPUT@', '@INPUT@'])
 
 nonindex_xml_files = source_xml_files + [systemd_directives_xml]
@@ -166,7 +170,7 @@ foreach tuple : xsltproc.found() ? [['systemd.directives', '7', systemd_directiv
                 input : xml,
                 output : html,
                 command : xslt_cmd + [custom_html_xsl, '@INPUT@'],
-                depends : [custom_entities_ent, p2],
+                depends : [man_page_depends, p2],
                 install : want_html and have_lxml,
                 install_dir : docdir / 'html')
         html_pages += p3
@@ -237,4 +241,4 @@ update_man_rules = custom_target(
         command : [update_man_rules_py,
                    '@0@/man/*.xml'.format(project_source_root),
                    '@0@/rules/meson.build'.format(meson.current_source_dir())],
-        depends : custom_entities_ent)
+        depends : man_page_depends)
index 50bbc9858f242e2c193cc4e6b40c80c322f12fed..00db6f8f7abd22a012bf2ce6d66458c0576e1839 100644 (file)
@@ -259,7 +259,7 @@ node /org/freedesktop/portable1 {
       see the <varname>MountImages=</varname> entry on
       <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
       and <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-      The <varname>flag</varname> parameter is currently unused and reserved for future purposes.</para>
+      </para>
 
       <para><function>DetachImage()</function> detaches a portable image from the system.
       This method takes an image path or name, and a boolean indicating whether the image to
index 54f0a18418ec5e2ab44a763fed62e8bcc038b1ae..a2b4490fc72bef86dea482d19ca58324aa6bcdfc 100644 (file)
@@ -439,32 +439,36 @@ node /org/freedesktop/resolve1 {
         <para>The four methods above accept and return a 64-bit flags value. In most cases passing 0 is sufficient
         and recommended. However, the following flags are defined to alter the look-up:</para>
 
-        <programlisting>
+        <programlisting>/* Input+Output: Protocol/scope */
 #define SD_RESOLVED_DNS               (UINT64_C(1) &lt;&lt;  0)
 #define SD_RESOLVED_LLMNR_IPV4        (UINT64_C(1) &lt;&lt;  1)
 #define SD_RESOLVED_LLMNR_IPV6        (UINT64_C(1) &lt;&lt;  2)
 #define SD_RESOLVED_MDNS_IPV4         (UINT64_C(1) &lt;&lt;  3)
 #define SD_RESOLVED_MDNS_IPV6         (UINT64_C(1) &lt;&lt;  4)
+
+/* Input: Restrictions */
 #define SD_RESOLVED_NO_CNAME          (UINT64_C(1) &lt;&lt;  5)
 #define SD_RESOLVED_NO_TXT            (UINT64_C(1) &lt;&lt;  6)
 #define SD_RESOLVED_NO_ADDRESS        (UINT64_C(1) &lt;&lt;  7)
 #define SD_RESOLVED_NO_SEARCH         (UINT64_C(1) &lt;&lt;  8)
-#define SD_RESOLVED_AUTHENTICATED     (UINT64_C(1) &lt;&lt;  9)
 #define SD_RESOLVED_NO_VALIDATE       (UINT64_C(1) &lt;&lt; 10)
 #define SD_RESOLVED_NO_SYNTHESIZE     (UINT64_C(1) &lt;&lt; 11)
 #define SD_RESOLVED_NO_CACHE          (UINT64_C(1) &lt;&lt; 12)
 #define SD_RESOLVED_NO_ZONE           (UINT64_C(1) &lt;&lt; 13)
 #define SD_RESOLVED_NO_TRUST_ANCHOR   (UINT64_C(1) &lt;&lt; 14)
 #define SD_RESOLVED_NO_NETWORK        (UINT64_C(1) &lt;&lt; 15)
-#define SD_RESOLVED_REQUIRE_PRIMARY   (UINT64_C(1) &lt;&lt; 16)
-#define SD_RESOLVED_CLAMP_TTL         (UINT64_C(1) &lt;&lt; 17)
+
+/* Output: Security */
+#define SD_RESOLVED_AUTHENTICATED     (UINT64_C(1) &lt;&lt;  9)
 #define SD_RESOLVED_CONFIDENTIAL      (UINT64_C(1) &lt;&lt; 18)
+
+/* Output: Origin */
 #define SD_RESOLVED_SYNTHETIC         (UINT64_C(1) &lt;&lt; 19)
 #define SD_RESOLVED_FROM_CACHE        (UINT64_C(1) &lt;&lt; 20)
 #define SD_RESOLVED_FROM_ZONE         (UINT64_C(1) &lt;&lt; 21)
 #define SD_RESOLVED_FROM_TRUST_ANCHOR (UINT64_C(1) &lt;&lt; 22)
 #define SD_RESOLVED_FROM_NETWORK      (UINT64_C(1) &lt;&lt; 23)
-        </programlisting>
+</programlisting>
 
         <para>On input, the first five flags control the protocols to use for the look-up. They refer to
         classic unicast DNS, LLMNR via IPv4/UDP and IPv6/UDP respectively, as well as MulticastDNS via
@@ -476,8 +480,8 @@ node /org/freedesktop/resolve1 {
         address lookup domains). It will route neither of these to Unicast DNS servers. Also, it will do
         LLMNR and Multicast DNS only on interfaces suitable for multicast.</para>
 
-        <para>On output, these five flags indicate which protocol was used to execute the operation, and hence
-        where the data was found.</para>
+        <para>On output, these five flags indicate which protocol was used to execute the operation, and
+        hence where the data was found.</para>
 
         <para>The primary use cases for these five flags are follow-up look-ups based on DNS data retrieved
         earlier. In this case it is often a good idea to limit the follow-up look-up to the protocol that was
@@ -496,8 +500,19 @@ node /org/freedesktop/resolve1 {
         <para>The NO_SEARCH flag turns off the search domain logic. It is only defined for input in
         <function>ResolveHostname()</function>. When specified, single-label hostnames are not qualified
         using defined search domains, if any are configured. Note that <function>ResolveRecord()</function>
-        will never qualify single-label domain names using search domains. Also note that
-        multi-label hostnames are never subject to search list expansion.</para>
+        will never qualify single-label domain names using search domains. Also note that multi-label
+        hostnames are never subject to search list expansion.</para>
+
+        <para>NO_VALIDATE can be set to disable validation via DNSSEC even if it would normally be
+        used.</para>
+
+        <para>The next four flags allow disabling certain sources during resolution. NO_SYNTHESIZE disables
+        synthetic records, e.g. the local host name, see section SYNTHETIC RECORDS in
+        <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        for more information. NO_CACHE disables the use of the cache of previously resolved records. NO_ZONE
+        disables answers using locally registered public LLMNR/mDNS resource records. NO_TRUST_ANCHOR
+        disables answers using locally configured trust anchors. NO_NETWORK requires all answers to be
+        provided without using the network, i.e. either from local sources or the cache.</para>
 
         <para>The AUTHENTICATED bit is defined only in the output flags of the four functions. If set, the
         returned data has been fully authenticated. Specifically, this bit is set for all DNSSEC-protected
@@ -510,31 +525,15 @@ node /org/freedesktop/resolve1 {
         trusted, or where there is proof that the data is "rightfully" unauthenticated (which includes cases
         where the underlying protocol or server does not support authenticating data).</para>
 
-        <para>NO_VALIDATE can be set to disable validation via DNSSEC even if it would normally be used.
-        </para>
-
-        <para>The next four flags allow disabling certain sources during resolution. NO_SYNTHESIZE disables
-        synthetic records, e.g. the local host name, see section SYNTHETIC RECORDS in
-        <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-        for more information. NO_CACHE disables the use of the cache of previously resolved records. NO_ZONE
-        disables answers using locally registered public LLMNR/mDNS resource records. NO_TRUST_ANCHOR
-        disables answers using locally configured trust anchors. NO_NETWORK requires all answers to be
-        provided without using the network, i.e. either from local sources or the cache.</para>
-
-        <para>With REQUIRE_PRIMARY the request must be answered from a "primary" answer, i.e. not from
-        resource records acquired as a side-effect of a previous transaction.</para>
-
-        <para>With CLAMP_TTL, if reply is answered from cache, the TTLs will be adjusted by age of cache
-        entry.</para>
+        <para>CONFIDENTIAL means the query was resolved via encrypted channels or never left this
+        system.</para>
 
-        <para>The next six bits flags are used in output and provide information about the source of the answer.
-        CONFIDENTIAL means the query was resolved via encrypted channels or never left this system.
-        FROM_SYNTHETIC means the query was (at least partially) synthesized.
-        FROM_CACHE means the query was answered (at least partially) using the cache.
-        FROM_ZONE means the query was answered (at least partially) using LLMNR/mDNS.
-        FROM_TRUST_ANCHOR means the query was answered (at least partially) using local trust anchors.
-        FROM_NETWORK means the query was answered (at least partially) using the network.
-        </para>
+        <para>The next five bits flags are used in output and provide information about the origin of the
+        answer. FROM_SYNTHETIC means the query was (at least partially) synthesized locally. FROM_CACHE means
+        the query was answered (at least partially) using the cache. FROM_ZONE means the query was answered
+        (at least partially) based on public, locally registered records. FROM_TRUST_ANCHOR means the query
+        was answered (at least partially) using local trust anchors. FROM_NETWORK means the query was
+        answered (at least partially) using the network.</para>
       </refsect3>
     </refsect2>
 
index 70273bbf64bf06343b617854645c79c8e77d6fd5..67ccf5f8036cebbfe83dd14cee7508491e5bbafe 100644 (file)
@@ -37,7 +37,7 @@
     unit and job objects or directly convert a unit name or job identifier to a bus path of the corresponding
     D-Bus object.</para>
 
-    <para>Properties exposing time values are usually encoded in microseconds (µs) on the bus, even if
+    <para>Properties exposing time values are usually encoded in microseconds (μs) on the bus, even if
     their corresponding settings in the unit files are in seconds.</para>
 
     <para>PID 1 uses <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink> to
@@ -3042,6 +3042,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(ss) LoadCredentialEncrypted = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly as ImportCredential = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as SupplementaryGroups = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s PAMName = '...';
@@ -3627,6 +3629,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property LoadCredentialEncrypted is not documented!-->
 
+    <!--property ImportCredential is not documented!-->
+
     <!--property SupplementaryGroups is not documented!-->
 
     <!--property PAMName is not documented!-->
@@ -4277,6 +4281,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@@ -5058,6 +5064,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(ss) LoadCredentialEncrypted = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly as ImportCredential = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as SupplementaryGroups = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s PAMName = '...';
@@ -5655,6 +5663,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property LoadCredentialEncrypted is not documented!-->
 
+    <!--property ImportCredential is not documented!-->
+
     <!--property SupplementaryGroups is not documented!-->
 
     <!--property PAMName is not documented!-->
@@ -6285,6 +6295,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@@ -6941,6 +6953,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(ss) LoadCredentialEncrypted = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly as ImportCredential = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as SupplementaryGroups = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s PAMName = '...';
@@ -7466,6 +7480,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property LoadCredentialEncrypted is not documented!-->
 
+    <!--property ImportCredential is not documented!-->
+
     <!--property SupplementaryGroups is not documented!-->
 
     <!--property PAMName is not documented!-->
@@ -8014,6 +8030,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
@@ -8797,6 +8815,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(ss) LoadCredentialEncrypted = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly as ImportCredential = ['...', ...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as SupplementaryGroups = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s PAMName = '...';
@@ -9308,6 +9328,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property LoadCredentialEncrypted is not documented!-->
 
+    <!--property ImportCredential is not documented!-->
+
     <!--property SupplementaryGroups is not documented!-->
 
     <!--property PAMName is not documented!-->
@@ -9842,6 +9864,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="LoadCredentialEncrypted"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ImportCredential"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="SupplementaryGroups"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="PAMName"/>
index 6cc786acf9e50367fb6a343e5163071728539f67..8deb12b190313d94b3503adf249b8917786ac13c 100644 (file)
           for light blue, or <literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue.
           </para></listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><varname>VENDOR_NAME=</varname></term>
+
+          <listitem><para>The name of the OS vendor. This is the name of the organization or company which
+          produces the OS. This field is optional.</para>
+
+          <para>This name is intended to be exposed in "About this system" UIs or software update UIs when
+          needed to distinguish the OS vendor from the OS itself. It is intended to be human readable.</para>
+
+          <para>Examples: <literal>VENDOR_NAME="Fedora Project"</literal> for Fedora Linux,
+          <literal>VENDOR_NAME="Canonical"</literal> for Ubuntu.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>VENDOR_URL=</varname></term>
+
+          <listitem><para>The homepage of the OS vendor. This field is optional. The
+          <varname>VENDOR_NAME=</varname> field should be set if this one is, although clients must be
+          robust against either field not being set.</para>
+
+          <para>The value should be in <ulink
+          url="https://tools.ietf.org/html/rfc3986">RFC3986 format</ulink>, and should be
+          <literal>http:</literal> or <literal>https:</literal> URLs. Only one URL shall be listed in the
+          setting.</para>
+
+          <para>Examples: <literal>VENDOR_URL="https://fedoraproject.org/"</literal>,
+          <literal>VENDOR_URL="https://canonical.com/"</literal>.</para></listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
index c966ca67bd28cd157db46b8c56454d7e3b886814..37a51b4760ee4a57bb49cfd56ddbe2eb1e970fb6 100644 (file)
         output.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><command>show-cache</command></term>
+
+        <listitem><para>Show current cache content, per scope. Use <option>--json=</option> to enable JSON
+        output.</para></listitem>
+      </varlistentry>
+
       <xi:include href="systemctl.xml" xpointer="log-level" />
     </variablelist>
   </refsect1>
index 2f17b89145d5b4c92cf926457246a2c85f696032..834eaeae85445b214c610e834811f282eb7f2be1 100644 (file)
@@ -91,7 +91,7 @@
       project='man-pages'><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
       supporting the <constant>CLOCK_MONOTONIC</constant>,
       <constant>CLOCK_REALTIME</constant>,
-      <constant>CLOCK_BOOTIME</constant> clocks, as well as the
+      <constant>CLOCK_BOOTTIME</constant> clocks, as well as the
       <constant>CLOCK_REALTIME_ALARM</constant> and
       <constant>CLOCK_BOOTTIME_ALARM</constant> clocks that can resume
       the system from suspend. When creating timer events a required
index a738f85bdec42410e41c1e91d5a399f47916f2a6..114b920c6c138f51a25e2d53b833267eb58f8815 100644 (file)
@@ -66,7 +66,7 @@
     <constant>POLLIN</constant>, <constant>POLLOUT</constant>, … events, or negative on error.
     </para>
 
-    <para><function>sd_bus_get_timeout()</function> returns the <emphasis>absolute</emphasis> time-out in µs,
+    <para><function>sd_bus_get_timeout()</function> returns the <emphasis>absolute</emphasis> time-out in μs,
     from which the relative time-out to pass to <function>poll()</function> (or a similar call) can be
     derived, when waiting for events on the specified bus connection. The returned timeout may be zero, in
     which case a subsequent I/O polling call should be invoked in non-blocking mode. The returned timeout may
index eaad91f52e8d30953ef8cf6654a00e23bd5ecd40..3c24a6f0a915c40e77b6f6b156ca864876b6d832 100644 (file)
@@ -47,7 +47,7 @@
     indicating that no work is pending on the connection. Internally, this call invokes <citerefentry
     project='man-pages'><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum></citerefentry>, to wait for I/O on
     the bus connection. If the <parameter>timeout_usec</parameter> parameter is specified, the call will block at most
-    for the specified amount of time in µs. Pass <constant>UINT64_MAX</constant> to permit it to sleep
+    for the specified amount of time in μs. Pass <constant>UINT64_MAX</constant> to permit it to sleep
     indefinitely.</para>
 
     <para>After each invocation of <function>sd_bus_wait()</function> the <function>sd_bus_process()</function> call
index 6031fee1b38b0cdd71a4cec3b4d52aa741d1ccb1..864cf9b268b8d64965c0c75eb3d3433c89c76915 100644 (file)
     <constant>CLOCK_REALTIME_ALARM</constant>, or <constant>CLOCK_BOOTTIME_ALARM</constant>. See
     <citerefentry><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details
     regarding the various types of clocks. The <parameter>usec</parameter> parameter specifies the earliest time, in
-    microseconds (µs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past
+    microseconds (μs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past
     is specified (including <constant>0</constant>), this timer source "fires" immediately and is ready to be
     dispatched. If the parameter is specified as <constant>UINT64_MAX</constant> the timer event will never elapse,
     which may be used as an alternative to explicitly disabling a timer event source with
     <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. The
-    <parameter>accuracy</parameter> parameter specifies an additional accuracy value in µs specifying how much the
-    timer event may be delayed. Use <constant>0</constant> to select the default accuracy (250ms). Use 1µs for maximum
-    accuracy. Consider specifying 60000000µs (1min) or larger for long-running events that may be delayed
+    <parameter>accuracy</parameter> parameter specifies an additional accuracy value in μs specifying how much the
+    timer event may be delayed. Use <constant>0</constant> to select the default accuracy (250ms). Use 1μs for maximum
+    accuracy. Consider specifying 60000000μs (1min) or larger for long-running events that may be delayed
     substantially. Picking higher accuracy values allows the system to coalesce timer events more aggressively,
     improving power efficiency.</para>
 
     <para><function>sd_event_source_get_time()</function> retrieves the configured time value of an event
     source created previously with <function>sd_event_add_time()</function> or
     <function>sd_event_add_time_relative()</function>. It takes the event source object and a pointer to a
-    variable to store the time in, relative to the selected clock's epoch, in µs. The returned value is
+    variable to store the time in, relative to the selected clock's epoch, in μs. The returned value is
     relative to the epoch, even if the event source was created with a relative time via
     <function>sd_event_add_time_relative()</function>.</para>
 
     <para><function>sd_event_source_set_time()</function> changes the time of an event source created
     previously with <function>sd_event_add_time()</function> or
     <function>sd_event_add_time_relative()</function>. It takes the event source object and a time relative
-    to the selected clock's epoch, in µs.</para>
+    to the selected clock's epoch, in μs.</para>
 
     <para><function>sd_event_source_set_time_relative()</function> is similar to
     <function>sd_event_source_set_time()</function>, but takes a time relative to the current time of the
     retrieves the configured accuracy value of an event source
     created previously with <function>sd_event_add_time()</function>. It
     takes the event source object and a pointer to a variable to store
-    the accuracy in. The accuracy is specified in µs.</para>
+    the accuracy in. The accuracy is specified in μs.</para>
 
     <para><function>sd_event_source_set_time_accuracy()</function>
     changes the configured accuracy of a timer event source created
     previously with <function>sd_event_add_time()</function>. It takes
-    the event source object and accuracy, in µs.</para>
+    the event source object and accuracy, in μs.</para>
 
     <para><function>sd_event_source_get_time_clock()</function>
     retrieves the configured clock of an event source created
index 70e980ab7b3ea0646287d89246d3bfc14567da3a..45037d13b25468022f6c2e0e783cf3d4056eaeeb 100644 (file)
@@ -53,7 +53,7 @@
     <citerefentry project='man-pages'><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
     for more information on the various clocks. The retrieved
     timestamp is stored in the <parameter>usec</parameter> parameter,
-    in µs since the clock's epoch. If this function is invoked before
+    in μs since the clock's epoch. If this function is invoked before
     the first event loop iteration, the current time is returned, as
     reported by <function>clock_gettime()</function>. To distinguish
     this case from a regular invocation the return value will be
index 8118121281c391c29c9a6edcb419cc6dd5a1cf0c..3fbda1c93e9bc1a967e624b755e37c401d93d24b 100644 (file)
     is no timeout to wait for this will fill in <constant>(uint64_t)
     -1</constant> instead. Note that <function>poll()</function> takes
     a relative timeout in milliseconds rather than an absolute timeout
-    in microseconds. To convert the absolute 'µs' timeout into
+    in microseconds. To convert the absolute 'μs' timeout into
     relative 'ms', use code like the following:</para>
 
     <programlisting>uint64_t t;
index 89f1729b13f0d835f7783a7d789cbc81c1f1691e..a286beaf45792981983d66ad383d76c26a7814ca 100644 (file)
         <term>MONOTONIC_USEC=…</term>
 
         <listitem><para>A field carrying the monotonic timestamp (as per
-        <constant>CLOCK_MONOTONIC</constant>) formatted in decimal in µs, when the notification message was
+        <constant>CLOCK_MONOTONIC</constant>) formatted in decimal in μs, when the notification message was
         generated by the client. This is typically used in combination with <literal>RELOADING=1</literal>,
         to allow the service manager to properly synchronize reload cycles. See
         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
index a3cc9befe8daea268a5b2d077129b9b5e4fd0b38..8639599eccc7dc903cdbef4b946421f31d28da89 100644 (file)
@@ -33,6 +33,7 @@
     <refname>sd_session_get_vt</refname>
     <refname>sd_session_get_remote_host</refname>
     <refname>sd_session_get_remote_user</refname>
+    <refname>sd_session_get_leader</refname>
     <refpurpose>Determine state of a specific session</refpurpose>
   </refnamediv>
 
         <paramdef>char **<parameter>display</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_session_get_leader</function></funcdef>
+        <paramdef>const char *<parameter>session</parameter></paramdef>
+        <paramdef>pid_t *<parameter>leader</parameter></paramdef>
+      </funcprototype>
+
       <funcprototype>
         <funcdef>int <function>sd_session_get_remote_host</function></funcdef>
         <paramdef>const char *<parameter>session</parameter></paramdef>
     <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     call after use.</para>
 
+    <para><function>sd_session_get_leader()</function> may be used to
+    determine the PID of the leader of the session identified by the
+    specified session identifier.</para>
+
     <para><function>sd_session_get_remote_host()</function> may be
     used to determine the remote hostname of the session identified by
     the specified session identifier. The returned string needs to be
     <function>sd_session_get_type()</function>,
     <function>sd_session_get_class()</function>,
     <function>sd_session_get_display()</function>,
+    <function>sd_session_get_leader()</function>,
     <function>sd_session_get_remote_user()</function>,
     <function>sd_session_get_remote_host()</function> and
     <function>sd_session_get_tty()</function> return 0 or
index b4a59f2ad10e6d864474ced35cf34d5bf04a91cb..352b3606d78633b9979ace5e977be305b75d4c47 100644 (file)
@@ -65,7 +65,7 @@
 
     <para>If the <parameter>usec</parameter> parameter is non-<constant>NULL</constant>,
     <function>sd_watchdog_enabled()</function> will write the timeout
-    in µs for the watchdog logic to it.</para>
+    in μs for the watchdog logic to it.</para>
 
     <para>To enable service supervision with the watchdog logic, use
     <varname>WatchdogSec=</varname> in service files. See
 
         <listitem><para>Set by the system manager for supervised
         process for which watchdog support is enabled, and contains
-        the watchdog timeout in µs. See above for
+        the watchdog timeout in μs. See above for
         details.</para></listitem>
       </varlistentry>
     </variablelist>
index 71c84958abe750742b4be2390d46955d56bf17a6..e72442e5a70dc2d039fd9bb3de0244a94aae858f 100644 (file)
     in the image are used.</para></listitem>
   </varlistentry>
 
+  <varlistentry id='esp-path'>
+    <term><option>--esp-path=</option></term>
+
+    <listitem>
+      <para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi/</filename>,
+      <filename>/boot/</filename>, and <filename>/boot/efi/</filename> are checked in turn. It is
+      recommended to mount the ESP to <filename>/efi/</filename>, if possible.</para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry id='boot-path'>
+    <term><option>--boot-path=</option></term>
+
+    <listitem>
+      <para>Path to the Extended Boot Loader partition, as defined in the
+      <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>.
+      If not specified, <filename>/boot/</filename> is checked. It is recommended to mount the Extended Boot
+      Loader partition to <filename>/boot/</filename>, if possible.</para>
+    </listitem>
+  </varlistentry>
+
 </variablelist>
index 29e5fc65c226405df6ae24942f3697f73c12b5e4..2d2434bbd066f44af337fa3ebc95b4ec23245a97 100644 (file)
@@ -1003,13 +1003,24 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           <term><command>mask <replaceable>UNIT</replaceable>…</command></term>
 
           <listitem>
-            <para>Mask one or more units, as specified on the command line. This will link these unit files to
-            <filename>/dev/null</filename>, making it impossible to start them. This is a stronger version of
-            <command>disable</command>, since it prohibits all kinds of activation of the unit, including enablement
-            and manual activation. Use this option with care. This honors the <option>--runtime</option> option to only
-            mask temporarily until the next reboot of the system. The <option>--now</option> option may be used to
-            ensure that the units are also stopped. This command expects valid unit names only, it does not accept unit
-            file paths.</para>
+            <para>Mask one or more units, as specified on the command line. This will link these unit files
+            to <filename>/dev/null</filename>, making it impossible to start them. This is a stronger version
+            of <command>disable</command>, since it prohibits all kinds of activation of the unit, including
+            enablement and manual activation. Use this option with care. This honors the
+            <option>--runtime</option> option to only mask temporarily until the next reboot of the
+            system. The <option>--now</option> option may be used to ensure that the units are also
+            stopped. This command expects valid unit names only, it does not accept unit file paths.</para>
+
+            <para>Note that this will create a symlink under the unit's name in
+            <filename>/etc/systemd/system/</filename> (in case <option>--runtime</option> is not specified)
+            or <filename>/run/systemd/system/</filename> (in case <option>--runtime</option> is
+            specified). If a matching unit file already exists under these directories this operation will
+            hence fail. This means that the operation is primarily useful to mask units shipped by the vendor
+            (as those are shipped in <filename>/usr/lib/systemd/system/</filename> and not the aforementioned
+            two directories), but typically doesn't work for units created locally (as those are typically
+            placed precisely in the two aforementioned directories). Similar restrictions apply for
+            <option>--user</option> mode, in which case the directories are below the user's home directory
+            however.</para>
           </listitem>
         </varlistentry>
 
@@ -2453,7 +2464,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           <variablelist>
             <varlistentry>
               <term><option>us</option></term>
-              <term><option>µs</option></term>
+              <term><option>μs</option></term>
               <listitem><para><literal>Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ</literal></para></listitem>
             </varlistentry>
           </variablelist>
@@ -2468,7 +2479,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
           <variablelist>
             <varlistentry>
               <term><option>us+utc</option></term>
-              <term><option>µs+utc</option></term>
+              <term><option>μs+utc</option></term>
               <listitem><para><literal>Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC</literal></para></listitem>
             </varlistentry>
           </variablelist>
index 27f77751fef9574dc40387841a10b70eb1ff9713..ffd6c1c4d866c0344a1df7335fe05157b9778412 100644 (file)
       <varlistentry>
         <term><option>--credential=</option></term>
         <listitem><para>Configure a credential to read the password from – if it exists. This may be used in
-        conjunction with the <varname>LoadCredential=</varname> and <varname>SetCredential=</varname>
-        settings in unit files. See
+        conjunction with the <varname>ImportCredential=</varname>, <varname>LoadCredential=</varname> and
+        <varname>SetCredential=</varname> settings in unit files. See
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details. If not specified, defaults to <literal>password</literal>. This option has no effect if no
         credentials directory is passed to the program (i.e. <varname>$CREDENTIALS_DIRECTORY</varname> is not
index c92a250ca22fc8bb12dc849b460b0e0faac8aede..4c98c6771a723113811eab6d92f6c74f069b6255 100644 (file)
@@ -192,7 +192,7 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
 
       <varlistentry>
         <term><varname>COREDUMP_TIMESTAMP=</varname></term>
-        <listitem><para>The time of the crash as reported by the kernel (in µs since the epoch).</para>
+        <listitem><para>The time of the crash as reported by the kernel (in μs since the epoch).</para>
         </listitem>
       </varlistentry>
 
index fbe62262af08555b950c27570ec7c8c46eed47ed..a5cfe0901a7e488a65bace090d5b239e663b65c2 100644 (file)
@@ -38,9 +38,9 @@
     processes. They are primarily used for passing cryptographic keys (both public and private) or
     certificates, user account information or identity information from the host to services.</para>
 
-    <para>Credentials are configured in unit files via the <varname>LoadCredential=</varname>,
-    <varname>SetCredential=</varname>, <varname>LoadCredentialEncrypted=</varname> and
-    <varname>SetCredentialEncrypted=</varname> settings, see
+    <para>Credentials are configured in unit files via the <varname>ImportCredential></varname>,
+    <varname>LoadCredential=</varname>, <varname>SetCredential=</varname>,
+    <varname>LoadCredentialEncrypted=</varname> and <varname>SetCredentialEncrypted=</varname> settings, see
     <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
     details.</para>
 
index 99846839678e8dac5c3459cb9d7dbde492679876..becb5f52ace9c51139ac6bed7daf078182ebc897 100644 (file)
     <title>Credentials</title>
 
     <para><command>systemd-firstboot</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
index 16b789869f67bd1b8e719bbb29e58ff68f2eebfe..1799961527dc79aa30e222282a59ff94ac9818f4 100644 (file)
         <literal>x86-64</literal>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--offline=</option><arg>BOOL</arg></term>
+
+        <listitem><para>Instructs <command>systemd-repart</command> to build the image offline. Takes a
+        boolean or <literal>auto</literal>. Defaults to <literal>auto</literal>. If enabled, the image is
+        built without using loop devices. This is useful to build images unprivileged or when loop devices
+        are not available. If disabled, the image is always built using loop devices. If
+        <literal>auto</literal>, <command>systemd-repart</command> will build the image online if possible
+        and fall back to building the image offline if loop devices are not available or cannot be accessed
+        due to missing permissions.</para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
       <xi:include href="standard-options.xml" xpointer="no-pager" />
index 7003c36db7e1e6ac71c8030fb02ff74ad7b8d930..05d20bbf35502da8731143aa440bce5ec223eeb0 100644 (file)
@@ -403,8 +403,8 @@ search foobar.com barbar.com
     <title>Credentials</title>
 
     <para><command>systemd-resolved</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
@@ -442,6 +442,27 @@ search foobar.com barbar.com
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>IP Ports</title>
+
+    <para>The <command>systemd-resolved</command> service listens on the following IP ports:</para>
+
+    <itemizedlist>
+      <listitem><para>Port 53 on IPv4 addresses 127.0.0.53 and 127.0.0.54 (both are on the local loopback
+      interface <literal>lo</literal>). This is the local DNS stub, as discussed above. Both UDP and TCP are
+      covered.</para></listitem>
+
+      <listitem><para>Port 5353 on all local addresses, both IPv4 and IPv6 (0.0.0.0 and ::0), for
+      MulticastDNS on UDP. Note that even though the socket is bound to all local interfaces via the selected
+      "wildcard" IP addresses, the incoming datagrams are filtered by the network interface they are coming
+      in on, and separate MulticastDNS link-local scopes are maintained for each, taking into consideration
+      whether MulticastDNS is enabled for the interface or not.</para></listitem>
+
+      <listitem><para>Port 5355 on all local addresses, both IPv4 and IP6 (0.0.0.0 and ::0), for LLMNR, on
+      both TCP and UDP. As with MulticastDNS filtering by incoming network interface is applied.</para></listitem>
+    </itemizedlist>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>
index fede8b092d730036c662bbb6f34f8c87f7d06582..4174184c152e63ba8e1cf9dff32b481bb4769789 100644 (file)
@@ -85,8 +85,8 @@
     <title>Credentials</title>
 
     <para><command>systemd-sysctl</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
index f7ee5e79d91fe083dd5b29febd72759818e9c4f1..34d3cab5c7e6582e913a81bab8afe58d8b04c20b 100644 (file)
     <title>Credentials</title>
 
     <para><command>systemd-sysusers</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname><varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
index 34e0a674720078d1f5cf132573adee8e34008bda..45fb6b716f1bcc7461348d39505c2f6fcfebf76b 100644 (file)
         <term><filename>/var/lib/systemd/timesync/clock</filename></term>
 
         <listitem>
-          <para>The modification time ("mtime") of this file is updated on each successful NTP synchronization
-          or after each <varname>SaveIntervalSec=</varname> time interval, as specified in
-          <citerefentry><refentrytitle>timesyncd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-          At the minimum, it will be set to the systemd build date. It is used to ensure that the system clock
-          remains roughly monotonic across reboots, in case no local RTC is available.</para>
+          <para>The modification time ("mtime") of this file is updated on each successful NTP
+          synchronization or after each <varname>SaveIntervalSec=</varname> time interval, as specified in
+          <citerefentry><refentrytitle>timesyncd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+          <para>When initializing, the local clock is advanced to the modification time of this file (if the
+          file timestamp is in the past this adjustment is not made). If the file does not exist yet, the
+          clock is instead advanced to the modification time of <filename>/usr/lib/clock-epoch</filename> –
+          if it exists – or to a time derived from the source tree at build time. This mechanism is used to
+          ensure that the system clock remains somewhat reasonably initialized and roughly monotonic across
+          reboots, in case no battery-buffered local RTC is available.</para>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><filename>/usr/lib/clock-epoch</filename></term>
+
+        <listitem><para>The modification time ("mtime") of this file is used for advancing the system clock
+        in case <filename>/var/lib/systemd/timesync/clock</filename> does not exist yet, see
+        above.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><filename>/run/systemd/timesync/synchronized</filename></term>
 
index 735f59cc11acc8b5a6d679b7edcfb36fd0269bdf..3a9699ff4b12e832acfd6e9ac9fee9f8dce43461 100644 (file)
     <title>Credentials</title>
 
     <para><command>systemd-tmpfiles</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
index 98d9e2ad01b2e14827a41c14f2d01479fa818ef7..f9f8327a68cdf2566d45ba390edec4b624444cc2 100644 (file)
@@ -53,8 +53,8 @@
     <title>Credentials</title>
 
     <para><command>systemd-vconsole-setup</command> supports the service credentials logic as implemented by
-    <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
-    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+    <varname>ImportCredential=</varname><varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+    (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
     details). The following credentials are used when passed in:</para>
 
     <variablelist>
index 9fb6c9b90841f2c79a5d21257c710c991d9c3bb1..b70b90d6671954be6fc4fa98fd0acc8c536508b7 100644 (file)
@@ -3286,6 +3286,25 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
         Credentials</ulink> documentation.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>ImportCredential=</varname><replaceable>GLOB</replaceable></term>
+
+        <listitem><para>Pass one or more credentials to the unit. Takes a credential name for which we'll
+        attempt to find a credential that the service manager itself received under the specified name —
+        which may be used to propagate credentials from an invoking environment (e.g. a container manager
+        that invoked the service manager) into a service. If the credential name is a glob, all credentials
+        matching the glob are passed to the unit. Matching credentials are searched for in the system
+        credentials, the encrypted system credentials, and under <filename>/etc/credstore/</filename>,
+        <filename>/run/credstore/</filename>, <filename>/usr/lib/credstore/</filename>,
+        <filename>/run/credstore.encrypted/</filename>, <filename>/etc/credstore.encrypted/</filename>, and
+        <filename>/usr/lib/credstore.encrypted/</filename> in that order. When multiple credentials of the
+        same name are found, the first one found is used.</para>
+
+        <para>When multiple credentials of the same name are found, credentials found by
+        <varname>LoadCredential=</varname> and <varname>LoadCredentialEncrypted=</varname> take priority over
+        credentials found by <varname>ImportCredential=</varname></para></listitem>.
+      </varlistentry>
+
       <varlistentry>
         <term><varname>SetCredential=</varname><replaceable>ID</replaceable>:<replaceable>VALUE</replaceable></term>
         <term><varname>SetCredentialEncrypted=</varname><replaceable>ID</replaceable>:<replaceable>VALUE</replaceable></term>
@@ -3307,10 +3326,13 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
         directly from plaintext credentials. For further details see
         <varname>LoadCredentialEncrypted=</varname> above.</para>
 
-        <para>If a credential of the same ID is listed in both <varname>LoadCredential=</varname> and
-        <varname>SetCredential=</varname>, the latter will act as default if the former cannot be
-        retrieved. In this case not being able to retrieve the credential from the path specified in
-        <varname>LoadCredential=</varname> is not considered fatal.</para></listitem>
+        <para>When multiple credentials of the same name are found, credentials found by
+        <varname>LoadCredential=</varname>, <varname>LoadCredentialEncrypted=</varname> and
+        <varname>ImportCredential=</varname> take priority over credentials found by
+        <varname>SetCredential=</varname>. As such, <varname>SetCredential=</varname> will act as default if
+        no credentials are found by any of the former. In this case not being able to retrieve the credential
+        from the path specified in <varname>LoadCredential=</varname> or
+        <varname>LoadCredentialEncrypted=</varname> is not considered fatal.</para></listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
@@ -3492,10 +3514,10 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
           <term><varname>$CREDENTIALS_DIRECTORY</varname></term>
 
           <listitem><para>An absolute path to the per-unit directory with credentials configured via
-          <varname>LoadCredential=</varname>/<varname>SetCredential=</varname>. The directory is marked
-          read-only and is placed in unswappable memory (if supported and permitted), and is only accessible to
-          the UID associated with the unit via <varname>User=</varname> or <varname>DynamicUser=</varname> (and
-          the superuser).</para></listitem>
+          <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>.
+          The directory is marked read-only and is placed in unswappable memory (if supported and permitted),
+          and is only accessible to the UID associated with the unit via <varname>User=</varname> or
+          <varname>DynamicUser=</varname> (and the superuser).</para></listitem>
         </varlistentry>
 
         <varlistentry>
@@ -4184,7 +4206,7 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
           <row>
             <entry>243</entry>
             <entry><constant>EXIT_CREDENTIALS</constant></entry>
-            <entry>Failed to set up unit's credentials. See <varname>LoadCredential=</varname> and <varname>SetCredential=</varname> above.</entry>
+            <entry>Failed to set up unit's credentials. See <varname>ImportCredential=</varname>, <varname>LoadCredential=</varname> and <varname>SetCredential=</varname> above.</entry>
           </row>
           <row>
             <entry>245</entry>
index cc851d31f98a710b276f17d971ea897059a4f9d7..39117f57069d2963aeb50133f06c1781249a32a6 100644 (file)
@@ -3,7 +3,8 @@
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
 
-<refentry id="systemd.link">
+<refentry id="systemd.link"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
   <refentryinfo>
     <title>systemd.link</title>
     <productname>systemd</productname>
                 credential <literal><replaceable>LINK</replaceable>.link.wol.password</literal> (e.g.,
                 <literal>60-foo.link.wol.password</literal>), and if the credential not found, then
                 read from <literal>wol.password</literal>. See
-                <varname>LoadCredential=</varname>/<varname>SetCredential=</varname> in
+                <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname> in
                 <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 for details. The password in the credential, must be 6 bytes in hex format with each
                 byte separated by a colon (<literal>:</literal>) like an Ethernet MAC address, e.g.,
                 <entry>Speed (Mbps)</entry>
                 <entry>Duplex Mode</entry>
               </row></thead>
-              <tbody>
-                <row><entry><option>10baset-half</option></entry>
-                <entry>10</entry><entry>half</entry></row>
-
-                <row><entry><option>10baset-full</option></entry>
-                <entry>10</entry><entry>full</entry></row>
-
-                <row><entry><option>100baset-half</option></entry>
-                <entry>100</entry><entry>half</entry></row>
-
-                <row><entry><option>100baset-full</option></entry>
-                <entry>100</entry><entry>full</entry></row>
-
-                <row><entry><option>1000baset-half</option></entry>
-                <entry>1000</entry><entry>half</entry></row>
-
-                <row><entry><option>1000baset-full</option></entry>
-                <entry>1000</entry><entry>full</entry></row>
-
-                <row><entry><option>10000baset-full</option></entry>
-                <entry>10000</entry><entry>full</entry></row>
-
-                <row><entry><option>2500basex-full</option></entry>
-                <entry>2500</entry><entry>full</entry></row>
-
-                <row><entry><option>1000basekx-full</option></entry>
-                <entry>1000</entry><entry>full</entry></row>
-
-                <row><entry><option>10000basekx4-full</option></entry>
-                <entry>10000</entry><entry>full</entry></row>
-
-                <row><entry><option>10000basekr-full</option></entry>
-                <entry>10000</entry><entry>full</entry></row>
-
-                <row><entry><option>10000baser-fec</option></entry>
-                <entry>10000</entry><entry>full</entry></row>
-
-                <row><entry><option>20000basemld2-full</option></entry>
-                <entry>20000</entry><entry>full</entry></row>
-
-                <row><entry><option>20000basekr2-full</option></entry>
-                <entry>20000</entry><entry>full</entry></row>
-              </tbody>
+              <xi:include href="ethtool-link-mode.xml" />
             </tgroup>
           </table>
 
index 610c11feb32a7e363938f4c99dc5cb706460d153..7836834efe01d33b816496fafc3d45b8cc23d892 100644 (file)
@@ -1362,7 +1362,7 @@ DeviceAllow=/dev/loop-control
         <varname>DefaultMemoryPressureThresholdSec=</varname> setting in
         <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         (which in turn defaults to 200ms). The specified value expects a time unit such as
-        <literal>ms</literal> or <literal>µs</literal>, see
+        <literal>ms</literal> or <literal>μs</literal>, see
         <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
         details on the permitted syntax.</para></listitem>
       </varlistentry>
index 646e1f21f067988439d0601625585286bc9d10d2..a183a9eedfb23d12caa233f55e57b0a873f706a0 100644 (file)
             <literal>MONOTONIC_USEC=</literal> set to the current monotonic time
             (i.e. <constant>CLOCK_MONOTONIC</constant> in
             <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>)
-            in µs, formatted as decimal string. Once reloading is complete another notification message must
+            in μs, formatted as decimal string. Once reloading is complete another notification message must
             be sent, containing <literal>READY=1</literal>. Using this service type and implementing this
             reload protocol is an efficient alternative to providing an <varname>ExecReload=</varname>
             command for reloading of the service's configuration.</para></listitem>
index 1f1f99800f1563171473552a828ea8bbaedc656a..7716e2898c5cda411ea35d12ec9825e04f6e20af 100644 (file)
 
       <varlistentry>
         <term><varname>Backlog=</varname></term>
-        <listitem><para>Takes an unsigned integer argument. Specifies
-        the number of connections to queue that have not been accepted
-        yet. This setting matters only for stream and sequential
-        packet sockets. See
-        <citerefentry><refentrytitle>listen</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        for details. Defaults to SOMAXCONN (128).</para></listitem>
+        <listitem><para>Takes an unsigned 32bit integer argument. Specifies the number of connections to
+        queue that have not been accepted yet. This setting matters only for stream and sequential packet
+        sockets. See
+        <citerefentry><refentrytitle>listen</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+        details. Note that this value is silently capped by the <literal>net.core.somaxconn</literal> sysctl,
+        which typically defaults to 4096. By default this is set to 4294967295, so that the sysctl takes full
+        effect.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry> to work
         unmodified with systemd socket activation.</para>
 
+        <para>Note that depending on this setting the services activated by units of this type are either
+        regular services (in case of <varname>Accept=</varname><option>no</option>) or instances of templated
+        services (in case of <varname>Accept=</varname><option>yes</option>). See the Description section
+        above for a more detailed discussion of the naming rules of triggered services.</para>
+
         <para>For IPv4 and IPv6 connections, the <varname>REMOTE_ADDR</varname> environment variable will
         contain the remote IP address, and <varname>REMOTE_PORT</varname> will contain the remote port. This
         is the same as the format used by CGI. For <constant>SOCK_RAW</constant>, the port is the IP
       <varlistentry>
         <term><varname>Timestamping=</varname></term>
         <listitem><para>Takes one of <literal>off</literal>, <literal>us</literal> (alias:
-        <literal>usec</literal>, <literal>µs</literal>) or <literal>ns</literal> (alias:
+        <literal>usec</literal>, <literal>μs</literal>) or <literal>ns</literal> (alias:
         <literal>nsec</literal>). This controls the <constant>SO_TIMESTAMP</constant> or
         <constant>SO_TIMESTAMPNS</constant> socket options, and enables whether ingress network traffic shall
         carry timestamping metadata. Defaults to <option>off</option>.</para></listitem>
index 07100b12b7ca06d5405bcaede699b4bdcdc912c3..6888f2226f6b279ceec2dfce82abf374e9497724 100644 (file)
@@ -47,7 +47,7 @@
     understood:</para>
 
     <itemizedlist>
-      <listitem><para>usec, us, µs</para></listitem>
+      <listitem><para>usec, us, μs</para></listitem>
       <listitem><para>msec, ms</para></listitem>
       <listitem><para>seconds, second, sec, s</para></listitem>
       <listitem><para>minutes, minute, min, m</para></listitem>
index 80dbd6410155f26f4c348951049e8b95c15e1b17..cdc9bca4c07b53607432d4713e76321e7b9100f3 100644 (file)
       <varlistentry>
         <term><varname>OnCalendar=</varname></term>
 
-        <listitem><para>Defines realtime (i.e. wallclock) timers with
-        calendar event expressions. See
-        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-        for more information on the syntax of calendar event
-        expressions. Otherwise, the semantics are similar to
+        <listitem><para>Defines realtime (i.e. wallclock) timers with calendar event expressions. See
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        more information on the syntax of calendar event expressions. Otherwise, the semantics are similar to
         <varname>OnActiveSec=</varname> and related settings.</para>
 
-        <para>Note that timers do not necessarily expire at the
-        precise time configured with this setting, as it is subject to
-        the <varname>AccuracySec=</varname> setting
-        below.</para>
+        <para>Note that timers do not necessarily expire at the precise time configured with this setting, as
+        it is subject to the <varname>AccuracySec=</varname> setting below.</para>
 
         <para>May be specified more than once, in which case the timer unit will trigger whenever any of the
         specified expressions elapse. Moreover calendar timers and monotonic timers (see above) may be
 
         <para>If the empty string is assigned to any of these options, the list of timers is reset (both
         <varname>OnCalendar=</varname> timers and monotonic timers, see above), and all prior assignments
-        will have no effect.</para></listitem>
+        will have no effect.</para>
+
+        <para>Note that calendar timers might be triggered at unexpected times if the system's realtime clock
+        is not set correctly. Specifically, on systems that lack a battery-buffered Realtime Clock (RTC) it
+        might be wise to enable <filename>systemd-time-wait-sync.service</filename> to ensure the clock is
+        adjusted to a network time source <emphasis>before</emphasis> the timer event is set up. Timer units
+        with at least one <varname>OnCalendar=</varname> expression are automatically ordered after
+        <filename>time-sync.target</filename>, which <filename>systemd-time-wait-sync.service</filename> is
+        ordered before.</para>
+
+        <para>When a system is temporarily put to sleep (i.e. system suspend or hibernation) the realtime
+        clock does not pause. When a calendar timer elapses while the system is sleeping it will not be acted
+        on immediately, but once the system is later resumed it will catch up and process all timers that
+        triggered while the system was sleeping. Note that if a calendar timer elapsed more than once while
+        the system was continously sleeping the timer will only result in a single service activation. If
+        <varname>WakeSystem=</varname> (see below) is enabled a calendar time event elapsing while the system
+        is suspended will cause the system to wake up (under the condition the system's hardware supports
+        time-triggered wake-up functionality).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 77c3cd24f8ad7c47c02ecf4d88520bfddf800e99..2eb88d02f7f14b8f15a5c60e1314263367c6f261 100644 (file)
       </varlistentry>
 
       <varlistentry>
+        <term><varname>OnSuccessJobMode=</varname></term>
         <term><varname>OnFailureJobMode=</varname></term>
 
         <listitem><para>Takes a value of
         <literal>ignore-dependencies</literal> or
         <literal>ignore-requirements</literal>. Defaults to
         <literal>replace</literal>. Specifies how the units listed in
-        <varname>OnFailure=</varname> will be enqueued. See
+        <varname>OnSuccess=</varname>/<varname>OnFailure=</varname> will be enqueued. See
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
         <option>--job-mode=</option> option for details on the
         possible values. If this is set to <literal>isolate</literal>,
         only a single unit may be listed in
-        <varname>OnFailure=</varname>.</para></listitem>
+        <varname>OnSuccess=</varname>/<varname>OnFailure=</varname>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 95dc1fef83c641bd6066370b0a04c55a6ca8cd87..2b1e9908463f4e2ceca63aa90bba7dd6e426cc87 100644 (file)
         <term><varname>systemd.set_credential=</varname></term>
 
         <listitem><para>Sets a system credential, which can then be propagated to system services using the
-        <varname>LoadCredential=</varname> setting, see
+        <varname>ImportCredential=</varname> or <varname>LoadCredential=</varname> setting, see
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details. Takes a pair of credential name and value, separated by a colon. Note that the kernel
         command line is typically accessible by unprivileged programs in
index 260c260f9886ac1209c2902a7acef66322ae77fa..1987e649ae6f6d18a465bdaa22e551dcc6315420 100644 (file)
           <row>
             <entry><literal>@t</literal></entry>
             <entry>File modification time</entry>
-            <entry>Formatted decimal integer, µs since UNIX epoch Jan 1st 1970</entry>
+            <entry>Formatted decimal integer, μs since UNIX epoch Jan 1st 1970</entry>
             <entry>Only relevant if target resource type chosen as <constant>regular-file</constant></entry>
           </row>
 
index 51a5fc82e33f6e8b9252c5b9626209f515320a78..6b36c78d3edbca27df72e517ecfa39736f2c7747 100644 (file)
@@ -10,7 +10,7 @@ project('systemd', 'c',
                 'localstatedir=/var',
                 'warning_level=2',
         ],
-        meson_version : '>= 0.53.2',
+        meson_version : '>= 0.56.0',
        )
 
 libsystemd_version = '0.36.0'
@@ -330,7 +330,7 @@ slow_tests = want_tests != 'false' and get_option('slow-tests')
 fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
 install_tests = get_option('install-tests')
 
-if add_languages('cpp', required : fuzzer_build)
+if add_languages('cpp', native : false, required : fuzzer_build)
         #  Used only for tests
         cxx = meson.get_compiler('cpp')
         cxx_cmd = ' '.join(cxx.cmd_array())
@@ -527,7 +527,7 @@ has_wstringop_truncation = cc.has_argument('-Wstringop-truncation')
 #####################################################################
 # compilation result tests
 
-conf.set('_GNU_SOURCE', true)
+conf.set('_GNU_SOURCE', 1)
 conf.set('__SANE_USERSPACE_TYPES__', true)
 conf.set10('HAVE_WSTRINGOP_TRUNCATION', has_wstringop_truncation)
 
@@ -735,7 +735,7 @@ foreach prog : progs
                                    '/usr/sbin/' + prog[0],
                                    '/sbin/' + prog[0],
                                    required: false)
-                path = exe.found() ? exe.path() : prog[1]
+                path = exe.found() ? exe.full_path() : prog[1]
         endif
         name = prog.length() > 2 ? prog[2] : prog[0].to_upper()
         conf.set_quoted(name, path)
@@ -1123,7 +1123,7 @@ else
                         r = find_program('clang', required : bpf_framework_required, version : '>= 10.0.0')
                         clang_found = r.found()
                         if clang_found
-                                clang = r.path()
+                                clang = r.full_path()
                         endif
                 else
                         clang_found = true
@@ -2173,6 +2173,8 @@ userspace = declare_dependency(
         link_args : userspace_c_ld_args,
 )
 
+man_page_depends = []
+
 ############################################################
 
 # binaries that have --help and are intended for use by humans,
@@ -2214,8 +2216,6 @@ subdir('src/udev')
 subdir('src/libudev')
 subdir('src/cryptsetup/cryptsetup-tokens')
 
-alias_target('devel', libsystemd_pc, libudev_pc)
-
 libsystemd = shared_library(
         'systemd',
         version : libsystemd_version,
@@ -2410,6 +2410,8 @@ subdir('rules.d')
 subdir('test')
 subdir('src/ukify/test')  # needs to be last for test_env variable
 
+alias_target('devel', libsystemd_pc, libudev_pc, systemd_pc, udev_pc)
+
 ############################################################
 
 # only static linking apart from libdl, to make sure that the
@@ -4376,17 +4378,17 @@ executable(
         install : true,
         install_dir : rootlibexecdir)
 
-kernel_install = custom_target(
+kernel_install = executable(
         'kernel-install',
-        input : kernel_install_in,
-        output : 'kernel-install',
-        command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
+        'src/kernel-install/kernel-install.c',
+        include_directories : includes,
+        link_with : [libshared],
+        dependencies : [userspace,
+                        versiondep],
+        install_rpath : rootpkglibdir,
         install : want_kernel_install,
-        install_mode : 'rwxr-xr-x',
         install_dir : bindir)
-if want_kernel_install
-        public_programs += exe
-endif
+public_programs += kernel_install
 
 ukify = custom_target(
         'ukify',
@@ -4397,19 +4399,22 @@ ukify = custom_target(
         install_mode : 'rwxr-xr-x',
         install_dir : rootlibexecdir)
 if want_ukify
-   public_programs += ukify
+        public_programs += ukify
 endif
 
 if want_tests != 'false' and want_kernel_install
-        args = [kernel_install.full_path(), loaderentry_install, uki_copy_install]
+        args = [kernel_install.full_path(), loaderentry_install.full_path(), uki_copy_install]
+        deps = [kernel_install, loaderentry_install]
         if want_ukify and boot_stubs.length() > 0
-                args += [ukify.full_path(), ukify_install, boot_stubs[0]]
+                args += [ukify.full_path(), ukify_install.full_path(), boot_stubs[0]]
+                deps += [ukify, ukify_install, boot_stubs[0]]
         endif
 
         test('test-kernel-install',
              test_kernel_install_sh,
              env : test_env,
-             args : args)
+             args : args,
+             depends: deps)
 endif
 
 ############################################################
@@ -4449,8 +4454,8 @@ foreach test : tests
                 versiondep,
         ]
 
-        # FIXME: Use fs.stem() with meson >= 0.54.0
-        name = '@0@'.format(sources[0]).split('/')[-1]
+        # FIXME: Drop .format with meson >= 0.59.0
+        name = fs.stem('@0@'.format(sources[0]))
         if not name.endswith('.cc')
                 deps += [userspace]
         endif
@@ -4589,8 +4594,8 @@ foreach fuzzer : fuzzers
         endif
         sources += fuzz_generated_directives
 
-        # FIXME: Use fs.stem() with meson >= 0.54.0
-        name = '@0@'.format(sources[0]).split('/')[-1].split('.')[0]
+        # FIXME: Drop .format with meson >= 0.59.0
+        name = fs.stem('@0@'.format(sources[0]))
 
         exe = executable(
                 name,
index 58de5fcf568cde52bf7ac06a68d171df147b1742..7dd02925c015a07bbeb8477637e50744034f9d01 100644 (file)
@@ -4,8 +4,8 @@
 # them without OOMing.
 
 [Match]
-Distribution=arch centos
-Release=rolling 8
+Distribution=|arch
+Distribution=|centos
 
 [Host]
 QemuMem=3G
index cde54e9e6ef4e11c3272bb2c6661e0295bc5d196..6b6ab8cccd45c523a4f02ba3a89c9fb0c69cbed0 100644 (file)
@@ -3,3 +3,6 @@
 [Match]
 Distribution=centos
 Release=8
+
+[Distribution]
+PackageManagerTrees=mkosi.reposdir:/etc/yum.repos.d
index f6141370ac39fed8e432a29090ebd9d28d58a419..7b0602f3b051577156fa2b4bbfb65bdbca14dcf1 100644 (file)
@@ -51,6 +51,7 @@ CONFIG_EFI_MIXED=y
 CONFIG_EFI_STUB=y
 CONFIG_EFI_ZBOOT=y
 CONFIG_EFI=y
+CONFIG_EROFS_FS=y
 CONFIG_EXPERT=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
@@ -98,6 +99,7 @@ CONFIG_IP6_NF_TARGET_REJECT=y
 CONFIG_ISO9660_FS=y
 CONFIG_KEXEC=y
 CONFIG_KPROBES=y
+CONFIG_KSM=y
 CONFIG_LOAD_UEFI_KEYS=y
 CONFIG_MAC80211=y
 CONFIG_MAGIC_SYSRQ=y
@@ -202,7 +204,6 @@ CONFIG_X86_MSR=y
 CONFIG_XFRM_USER=y
 CONFIG_XFS_FS=y
 CONFIG_XFS_POSIX_ACL=y
-CONFIG_KSM=y
 
 # CONFIG_WIRELESS is not set
 # CONFIG_WLAN is not set
index ad44d46529fdd3aead957e54f22398f4722a2ef4..283369ff109a35c247ed904b09e2526c0b821a9e 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Distribution=centos fedora
+Distribution=|centos
+Distribution=|fedora
 
 [Content]
 Packages=
index 1c4cb2d7acca7c2373d423dfceb20e903d2562f6..63b1daae0a51942e6fcc0eb981a1cbfef2b12a57 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Distribution=debian ubuntu
+Distribution=|debian
+Distribution=|ubuntu
 
 [Content]
 Packages=
index 40fd6c40053ab5bca0a0ca217011ae61a69b5998..77e4896c1765192d6731b787c78d45a85f1f514f 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Bootable=auto,yes
+Bootable=|auto
+Bootable=|yes
 
 [Output]
 Format=cpio
index a2a935226692f5b30c17b208bb26eebeabffb871..58e48989f3efee5062938a66d7584bb923390781 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Distribution=arch debian fedora opensuse ubuntu
+Distribution=!centos
 
 [Output]
 CompressOutput=zst
index bb158eb05911a956e9316a7b41d29dc0e0c3ea94..1277ad4034994e57f475d87423eaaf4fd6a0c3bc 100644 (file)
@@ -26,6 +26,7 @@ Packages=
         openssl
         qrencode
         sed
+        socat
         strace
         tmux
         tree
index b0bbcf0c6ade3addb3d8b27e6071dbd1a691fd66..0b15677ff29d3bd8d9fd8063e7332b92ea3d00fd 100644 (file)
@@ -5,6 +5,7 @@ Distribution=arch
 
 [Content]
 Packages=
+        bpf
         btrfs-progs
         compsize
         dhcp
index 02e11d095f0b0cd72f1906716fe846b3ea52594b..cb68c8dd1ad9b12d126d048c2129a36d959513d0 100644 (file)
@@ -1,10 +1,12 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Distribution=centos fedora
+Distribution=|centos
+Distribution=|fedora
 
 [Content]
 Packages=
+        bpftool
         cryptsetup
         dhcp-server
         dnf
index 071e46fd44d08a763250e6be305822ee3f95a373..588f833c8f4a9b8c25ff1f63492c4b6c88ed01d4 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
 [Match]
-Distribution=debian ubuntu
+Distribution=|debian
+Distribution=|ubuntu
 
 [Content]
 Packages=
index 3eb7a5453e3a81a0fba0ae1205a6c2c8e6e67c73..d4cd53e6f2c336a36ffdaaadbc3ded7a33820f8f 100644 (file)
@@ -5,4 +5,5 @@ Distribution=debian
 
 [Content]
 Packages=
+        bpftool
         linux-image-cloud-amd64
index 54b79e06d14e8f4c4e67e38dbd1ee2d7c1118629..60a2b6dbfc5accba722e98cb9ccaf6473196c19c 100644 (file)
@@ -5,6 +5,7 @@ Distribution=opensuse
 
 [Content]
 Packages=
+        bpftool
         btrfs-progs
         cryptsetup
         dbus-broker
index e677797c734134e886303d0aad6da33ad26efa38..3290987824c822fec75d74e0cccd8c6e6d024633 100644 (file)
@@ -8,3 +8,5 @@ Packages=
         # We would like to use linux-image-kvm but it does not have support for dm-verity
         # See https://bugs.launchpad.net/ubuntu/+source/linux-meta-kvm/+bug/2019040.
         linux-image-generic
+        linux-tools-common
+        linux-tools-generic
index b11b13f70926266e0ccf045bea2c38fe9171427d..14b18727efcc01c886fe90f52b7d65df36d9e6de 100644 (file)
@@ -2,7 +2,8 @@
 
 [Match]
 PathExists=../../mkosi.kernel/
-Distribution=centos fedora
+Distribution=|centos
+Distribution=|fedora
 
 [Content]
 Packages=
index 653efa8f0c18fc38d52902c0baf78efa962dd880..f9413f1da64fc26386e182e05aa9c665d32848ca 100644 (file)
@@ -2,7 +2,8 @@
 
 [Match]
 PathExists=../../mkosi.kernel/
-Distribution=debian ubuntu
+Distribution=|debian
+Distribution=|ubuntu
 
 [Content]
 Packages=
index b77d52d8282935cd4302fbc23c848215350b52b7..30fb30fde78123ef02c6dd5495d0d9f2b6a05979 100755 (executable)
@@ -1,8 +1,6 @@
 #!/bin/bash -eux
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
-rm -f /testok
-
 # TODO: Figure out why this is failing
 systemctl reset-failed systemd-vconsole-setup.service
 
@@ -20,4 +18,6 @@ fi
 # Exit with non-zero EC if the /failed-services file is not empty (we have -e set)
 [[ ! -s /failed-services ]]
 
-touch /testok
+# On success, exit with 123 so that we can check that we receive the actual exit code from the script on the
+# host.
+exit 123
index edba96c668c721e1cfb1d68cc275199d1d795464..6224087ebefd06c43acfc268cf8acc33b1a126db 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -2,13 +2,13 @@
 #
 # Italian translation for systemd package
 # Traduzione in italiano per il pacchetto systemd
-# Daniele Medri <dmedri@gmail.com>, 2013-2022.
+# Daniele Medri <dmedri@gmail.com>, 2013-2023.
 msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-10-20 10:35+0200\n"
-"PO-Revision-Date: 2022-04-26 15:57+0200\n"
+"POT-Creation-Date: 2023-06-05 11:40+0200\n"
+"PO-Revision-Date: 2023-06-05 11:44+0200\n"
 "Last-Translator: Daniele Medri <dmedri@gmail.com>\n"
 "Language-Team: italian\n"
 "Language: it\n"
@@ -16,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Poedit 2.4.2\n"
+"X-Generator: Poedit 3.2.2\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -69,6 +69,17 @@ msgstr "Ricarica lo stato di systemd"
 msgid "Authentication is required to reload the systemd state."
 msgstr "Autenticazione richiesta per ricaricare lo stato di systemd."
 
+#: src/core/org.freedesktop.systemd1.policy.in:74
+msgid "Dump the systemd state without rate limits"
+msgstr "Eseguire il dump dello stato di systemd senza limiti di frequenza"
+
+#: src/core/org.freedesktop.systemd1.policy.in:75
+msgid ""
+"Authentication is required to dump the systemd state without rate limits."
+msgstr ""
+"L'autenticazione è richiesta per il dump dello stato di systemd senza limiti "
+"di frequenza."
+
 #: src/home/org.freedesktop.home1.policy:13
 msgid "Create a home area"
 msgstr "Crea un'area home"
@@ -934,23 +945,23 @@ msgstr ""
 "Autenticazione richiesta per verificare se la sincronizzazione dell'orario "
 "in rete deve essere attivata."
 
-#: src/core/dbus-unit.c:359
+#: src/core/dbus-unit.c:364
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Autenticazione richiesta per avviare '$(unit)'."
 
-#: src/core/dbus-unit.c:360
+#: src/core/dbus-unit.c:365
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Autenticazione richiesta per fermare '$(unit)'."
 
-#: src/core/dbus-unit.c:361
+#: src/core/dbus-unit.c:366
 msgid "Authentication is required to reload '$(unit)'."
 msgstr "Autenticazione richiesta per ricaricare '$(unit)'."
 
-#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363
+#: src/core/dbus-unit.c:367 src/core/dbus-unit.c:368
 msgid "Authentication is required to restart '$(unit)'."
 msgstr "Autenticazione richiesta per riavviare '$(unit)'."
 
-#: src/core/dbus-unit.c:546
+#: src/core/dbus-unit.c:565
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
@@ -958,16 +969,16 @@ msgstr ""
 "Autenticazione richiesta per inviare un segnale UNIX ai processi di "
 "'$(unit)'."
 
-#: src/core/dbus-unit.c:576
+#: src/core/dbus-unit.c:595
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '$(unit)'."
 
-#: src/core/dbus-unit.c:608
+#: src/core/dbus-unit.c:627
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr "Autenticazione richiesta per configurare le proprietà di '$(unit)'."
 
-#: src/core/dbus-unit.c:714
+#: src/core/dbus-unit.c:728
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
@@ -975,7 +986,7 @@ msgstr ""
 "Autenticazione richiesta per eliminare i file e le directory associate a "
 "'$(unit)'."
 
-#: src/core/dbus-unit.c:762
+#: src/core/dbus-unit.c:776
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
 msgstr ""
index 24d3cdef22e13df014741b35b3e81aef664652b7..f6f04f4207abaefbbc31acc833d8d25972d8d193 100644 (file)
--- a/po/ko.po
+++ b/po/ko.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-10-20 10:35+0200\n"
-"PO-Revision-Date: 2023-06-03 15:48+0000\n"
+"PO-Revision-Date: 2023-06-13 20:18+0000\n"
 "Last-Translator: 김인수 <simmon@nplob.com>\n"
 "Language-Team: Korean <https://translate.fedoraproject.org/projects/systemd/"
 "master/ko/>\n"
@@ -109,7 +109,7 @@ msgstr "사용자 홈 영역을 조정하려면 인증이 필요합니다."
 
 #: src/home/org.freedesktop.home1.policy:63
 msgid "Change password of a home area"
-msgstr "홈 영역 호 변경"
+msgstr "홈 영역 비밀번호 변경"
 
 #: src/home/org.freedesktop.home1.policy:64
 msgid ""
index 2b8db9d476f1e77c5a4a480dc79e5d76b6ab451d..798cad46b0ee76cffa372989ff84850594cb7d62 100644 (file)
@@ -18,6 +18,7 @@ enable machines.target
 enable getty@.service
 enable systemd-timesyncd.service
 enable systemd-networkd.service
+enable systemd-networkd-wait-online.service
 enable systemd-network-generator.service
 enable systemd-resolved.service
 enable systemd-homed.service
@@ -36,7 +37,6 @@ enable reboot.target
 disable rescue.target
 disable exit.target
 
-disable systemd-networkd-wait-online.service
 disable systemd-time-wait-sync.service
 disable systemd-boot-check-no-failures.service
 disable proc-sys-fs-binfmt_misc.mount
index 3dbba1f850dbee233c8f0ae14bbda5642f6adb21..c0defc31de729e90c6d24ec64445507eae68d504 100644 (file)
@@ -65,10 +65,12 @@ SUBSYSTEM=="udc", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="usb-gadget
 # Apply sysctl variables to network devices (and only to those) as they appear.
 ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="{{ROOTLIBEXECDIR}}/systemd-sysctl --prefix=/net/ipv4/conf/$name --prefix=/net/ipv4/neigh/$name --prefix=/net/ipv6/conf/$name --prefix=/net/ipv6/neigh/$name"
 
+{% if ENABLE_BACKLIGHT %}
 # Pull in backlight save/restore for all backlight devices and
 # keyboard backlights
 SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@backlight:$name.service"
 SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@leds:$name.service"
+{% endif %}
 
 # Pull in rfkill save/restore for all rfkill devices
 SUBSYSTEM=="rfkill", ENV{SYSTEMD_RFKILL}="1"
index 5fe7611b71dad688eddb83963ac9954d2590bc05..24cb785e6beb95cff8dcd21a61b1a40413182785 100644 (file)
@@ -4,7 +4,7 @@ bashcompletiondir = get_option('bashcompletiondir')
 if bashcompletiondir == ''
         bash_completion = dependency('bash-completion', required : false)
         if bash_completion.found()
-                bashcompletiondir = bash_completion.get_pkgconfig_variable('completionsdir')
+                bashcompletiondir = bash_completion.get_variable(pkgconfig : 'completionsdir')
         else
                 bashcompletiondir = datadir / 'bash-completion/completions'
         endif
index 23422a9a4e61070aad2a20056dca5594ededc03c..65babe2c083bdc7227d9da08b40a3e8309b6eb3f 100644 (file)
@@ -12,8 +12,8 @@ _localectl_set-locale() {
 
     local expl suf
     _locales=( ${(f)"$(_call_program locales "$service" list-locales)"} )
-    compset -P1 '*='
     if [[ -prefix 1 *\= ]]; then
+        compset -P1 '*='
         local conf=${PREFIX%%\=*}
         _wanted locales expl "locales configs" \
             _combination localeconfs  confs=$conf locales "$@" -
index f027c31208d2afb6216bc1cc6e9cd0d5a211824a..fadf1dacaf2b5b5fa05d6c07321e082e36c5cb65 100644 (file)
@@ -19,7 +19,7 @@ static void help(void) {
                "  -h --help             Show this help\n"
                "     --version          Show package version\n"
                "  -v --verbose          Show state as text\n"
-               "     --low              Checks if battery is discharing and low\n",
+               "     --low              Check if battery is discharging and low\n",
                program_invocation_short_name);
 }
 
index de41d7b641d24cc07f2696c97ec6a65bb81cba9c..b45842f1cbc3df5a09c0f3d8e76d6bfc0c0002b8 100644 (file)
@@ -44,8 +44,8 @@ static int help(void) {
                "     --id=ID          Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
                "     --keyname=NAME   Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
                "     --credential=NAME\n"
-               "                      Credential name for LoadCredential=/SetCredential=\n"
-               "                      credentials\n"
+               "                      Credential name for ImportCredential=, LoadCredential= or\n"
+               "                      SetCredential= credentials\n"
                "     --timeout=SEC    Timeout in seconds\n"
                "     --echo=yes|no|masked\n"
                "                      Control whether to show password while typing (echo)\n"
index 600e2b9d33c7f82e8241da71360783a804f72c05..a4d9edb4c9705ec2c7f4d9aa29ac8e3ffa395f2e 100644 (file)
@@ -81,7 +81,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
         const char *todo;
         int r;
 
-        assert(path);
         assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT));
         assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
         assert(!FLAGS_SET(flags, CHASE_TRAIL_SLASH|CHASE_EXTRACT_FILENAME));
@@ -618,11 +617,51 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
         return 0;
 }
 
+int chase_extract_filename(const char *path, const char *root, char **ret) {
+        int r;
+
+        /* This is similar to path_extract_filename(), but takes root directory.
+         * The result should be consistent with chase() with CHASE_EXTRACT_FILENAME. */
+
+        assert(path);
+        assert(ret);
+
+        if (isempty(path))
+                return -EINVAL;
+
+        if (!path_is_absolute(path))
+                return -EINVAL;
+
+        if (!empty_or_root(root)) {
+                _cleanup_free_ char *root_abs = NULL;
+
+                r = path_make_absolute_cwd(root, &root_abs);
+                if (r < 0)
+                        return r;
+
+                path = path_startswith(path, root_abs);
+                if (!path)
+                        return -EINVAL;
+        }
+
+        if (!isempty(path)) {
+                r = path_extract_filename(path, ret);
+                if (r != -EADDRNOTAVAIL)
+                        return r;
+        }
+
+        char *fname = strdup(".");
+        if (!fname)
+                return -ENOMEM;
+
+        *ret = fname;
+        return 0;
+}
+
 int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
         _cleanup_close_ int path_fd = -EBADF;
         _cleanup_free_ char *p = NULL, *fname = NULL;
         mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
-        const char *q;
         int r;
 
         assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
@@ -640,13 +679,10 @@ int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, i
                 return r;
         assert(path_fd >= 0);
 
-        assert_se(q = path_startswith(p, empty_to_root(root)));
-        if (isempty(q))
-                q = ".";
-
-        if (!FLAGS_SET(chase_flags, CHASE_PARENT)) {
-                r = path_extract_filename(q, &fname);
-                if (r < 0 && r != -EADDRNOTAVAIL)
+        if (!FLAGS_SET(chase_flags, CHASE_PARENT) &&
+            !FLAGS_SET(chase_flags, CHASE_EXTRACT_FILENAME)) {
+                r = chase_extract_filename(p, root, &fname);
+                if (r < 0)
                         return r;
         }
 
index f37e8368227c75b7abd4df86373f1282b8d7f572..cfc714b9f774cc570cf0c5d8323c6eb811ba13e9 100644 (file)
@@ -43,6 +43,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b);
 int chase(const char *path_with_prefix, const char *root, ChaseFlags chase_flags, char **ret_path, int *ret_fd);
 
 int chaseat_prefix_root(const char *path, const char *root, char **ret);
+int chase_extract_filename(const char *path, const char *root, char **ret);
 
 int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path);
 int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);
index 3c66a3e0c83bcddd293121cb74719a426f3e48bf..c59fb8a84e922f3a7242806123aba7b63c35e743 100644 (file)
@@ -9,29 +9,29 @@
 #include "chattr-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
+#include "fs-util.h"
 #include "macro.h"
 #include "string-util.h"
 
-int chattr_full(const char *path,
-                int fd,
-                unsigned value,
-                unsigned mask,
-                unsigned *ret_previous,
-                unsigned *ret_final,
-                ChattrApplyFlags flags) {
+int chattr_full(
+              int dir_fd,
+              const char *path,
+              unsigned value,
+              unsigned mask,
+              unsigned *ret_previous,
+              unsigned *ret_final,
+              ChattrApplyFlags flags) {
 
-        _cleanup_close_ int fd_will_close = -EBADF;
+        _cleanup_close_ int fd = -EBADF;
         unsigned old_attr, new_attr;
         int set_flags_errno = 0;
         struct stat st;
 
-        assert(path || fd >= 0);
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
 
-        if (fd < 0) {
-                fd = fd_will_close = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
-                if (fd < 0)
-                        return -errno;
-        }
+        fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, /* xopen_flags = */ 0, /* mode = */ 0);
+        if (fd < 0)
+                return -errno;
 
         if (fstat(fd, &st) < 0)
                 return -errno;
index 82f91c66d9e55e07d221088c2628980b15b540e6..c1ee63b4fae94927a7344ee12343ee7d30d9ef5a 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <fcntl.h>
 #include <linux/fs.h>
 #include <stdbool.h>
 #include <stddef.h>
@@ -39,13 +40,15 @@ typedef enum ChattrApplyFlags {
         CHATTR_WARN_UNSUPPORTED_FLAGS = 1 << 1,
 } ChattrApplyFlags;
 
-int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags);
-
+int chattr_full(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags);
+static inline int chattr_at(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *previous) {
+        return chattr_full(dir_fd, path, value, mask, previous, NULL, 0);
+}
 static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) {
-        return chattr_full(NULL, fd, value, mask, previous, NULL, 0);
+        return chattr_full(fd, NULL, value, mask, previous, NULL, 0);
 }
 static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) {
-        return chattr_full(path, -1, value, mask, previous, NULL, 0);
+        return chattr_full(AT_FDCWD, path, value, mask, previous, NULL, 0);
 }
 
 int read_attr_fd(int fd, unsigned *ret);
@@ -57,5 +60,5 @@ int read_attr_path(const char *p, unsigned *ret);
 #define CHATTR_SECRET_FLAGS (FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL)
 
 static inline int chattr_secret(int fd, ChattrApplyFlags flags) {
-        return chattr_full(NULL, fd, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
+        return chattr_full(fd, NULL, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
 }
index 2c3ff12efebad370b4f05d7d284287434997c0db..5c30482e580e135dd8c945e4ec59a53fff5ef4c1 100644 (file)
@@ -1,8 +1,14 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-extern void __gcov_dump(void);
-extern void __gcov_reset(void);
+/* Use the coverage-related tweaks below only for C stuff as they're not really
+ * C++ compatible, and the only thing that is built with a C++ compiler is
+ * the lone test-bus-vtable-cc unit test.
+ */
+#ifndef __cplusplus
+
+void __gcov_dump(void);
+void __gcov_reset(void);
 
 /* When built with --coverage (gcov) we need to explicitly call __gcov_dump()
  * in places where we use _exit(), since _exit() skips at-exit hooks resulting
@@ -12,7 +18,7 @@ extern void __gcov_reset(void);
  * explicitly on the compiler command line via the -include directive (only
  * when built with -Db_coverage=true)
  */
-extern void _exit(int);
+void _exit(int);
 
 static inline _Noreturn void _coverage__exit(int status) {
         __gcov_dump();
@@ -28,8 +34,8 @@ static inline _Noreturn void _coverage__exit(int status) {
  * [0] https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/libgcov-interface.c;h=b2ee930864183b78c8826255183ca86e15e21ded;hb=HEAD
  */
 
-extern int execveat(int, const char *, char * const [], char * const [], int);
-extern int execvpe(const char *, char * const [], char * const []);
+int execveat(int, const char *, char * const [], char * const [], int);
+int execvpe(const char *, char * const [], char * const []);
 
 static inline int _coverage_execveat(
                         int dirfd,
@@ -56,3 +62,5 @@ static inline int _coverage_execvpe(
         return r;
 }
 #define execvpe(f,a,e) _coverage_execvpe(f, a, e)
+
+#endif
index 907bfeb60024b9d4252ee1506a9f0e9039146cb3..d9ef7ec9326dd0bd49f73e6eeaeb17e045386a4d 100644 (file)
@@ -891,12 +891,21 @@ int fd_get_diskseq(int fd, uint64_t *ret) {
         return 0;
 }
 
-int dir_fd_is_root(int dir_fd) {
+int path_is_root_at(int dir_fd, const char *path) {
         STRUCT_NEW_STATX_DEFINE(st);
         STRUCT_NEW_STATX_DEFINE(pst);
+        _cleanup_close_ int fd = -EBADF;
         int r;
 
-        assert(dir_fd >= 0);
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
+        if (!isempty(path)) {
+                fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC);
+                if (fd < 0)
+                        return errno == ENOTDIR ? false : -errno;
+
+                dir_fd = fd;
+        }
 
         r = statx_fallback(dir_fd, ".", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st.sx);
         if (r == -ENOTDIR)
index 2f59e334c5c12051405b3bfa94ef3ac2fbe80aa7..c870a1b8990d6ca21d870c260b0e51913b12958d 100644 (file)
@@ -101,9 +101,12 @@ int fd_is_opath(int fd);
 int read_nr_open(void);
 int fd_get_diskseq(int fd, uint64_t *ret);
 
-int dir_fd_is_root(int dir_fd);
+int path_is_root_at(int dir_fd, const char *path);
+static inline int dir_fd_is_root(int dir_fd) {
+        return path_is_root_at(dir_fd, NULL);
+}
 static inline int dir_fd_is_root_or_cwd(int dir_fd) {
-        return dir_fd == AT_FDCWD ? true : dir_fd_is_root(dir_fd);
+        return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL);
 }
 
 /* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
index 78e92609c6b9a97fa6e6f75af172043b8d335569..1cf0f5b945ee9a365efb8f8ee10dc3bff8529888 100644 (file)
@@ -1097,7 +1097,6 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
         int r;
 
         assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
-        assert(path);
 
         if (isempty(path)) {
                 assert(!FLAGS_SET(open_flags, O_CREAT|O_EXCL));
index 5577c6bc78af450b83ccb6887e70a4d4a3cdd467..1decb4827fe991bc5da6c52a33e228511b687285 100644 (file)
@@ -92,6 +92,7 @@ basic_sources = files(
         'terminal-util.c',
         'time-util.c',
         'tmpfile-util.c',
+        'uid-alloc-range.c',
         'uid-range.c',
         'unit-def.c',
         'unit-file.c',
index 39e9f2c668c938a87f3d33efe77865841756cd24..6203b7995972b587e1ba5b65835458ab99fd3859 100644 (file)
@@ -98,7 +98,7 @@ int proc_cmdline(char **ret) {
         if (detect_container() > 0)
                 return get_process_cmdline(1, SIZE_MAX, 0, ret);
         else
-                return read_one_line_file("/proc/cmdline", ret);
+                return read_full_file("/proc/cmdline", ret, NULL);
 }
 
 static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
@@ -128,7 +128,7 @@ static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
         } else {
                 _cleanup_free_ char *s = NULL;
 
-                r = read_one_line_file("/proc/cmdline", &s);
+                r = read_full_file("/proc/cmdline", &s, NULL);
                 if (r < 0)
                         return r;
 
index bcba5a5208a6da62f4a4647ae1808c6b30d9041e..d7cfcd9105bf4ed27b964fe9295b4f035c48ac33 100644 (file)
@@ -165,7 +165,7 @@ int procfs_cpu_get_usage(nsec_t *ret) {
                 (uint64_t) irq_ticks + (uint64_t) softirq_ticks +
                 (uint64_t) guest_ticks + (uint64_t) guest_nice_ticks;
 
-        /* Let's reduce this fraction before we apply it to avoid overflows when converting this to µsec */
+        /* Let's reduce this fraction before we apply it to avoid overflows when converting this to μsec */
         gcd = calc_gcd64(NSEC_PER_SEC, ticks_per_second);
 
         a = (uint64_t) NSEC_PER_SEC / gcd;
index 9040ff7c53471dcb38d0dcc68ea09315bd86d620..d82d9fe78a6d7d3953be3e3ae74d9edca2357534 100644 (file)
@@ -1522,13 +1522,20 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
         _cleanup_free_ char *n = NULL;
         char *e, *cid_start;
         unsigned port, cid;
-        int r;
+        int type, r;
 
         assert(ret_address);
         assert(s);
 
-        cid_start = startswith(s, "vsock:");
-        if (!cid_start)
+        if ((cid_start = startswith(s, "vsock:")))
+                type = 0;
+        else if ((cid_start = startswith(s, "vsock-dgram:")))
+                type = SOCK_DGRAM;
+        else if ((cid_start = startswith(s, "vsock-seqpacket:")))
+                type = SOCK_SEQPACKET;
+        else if ((cid_start = startswith(s, "vsock-stream:")))
+                type = SOCK_STREAM;
+        else
                 return -EPROTO;
 
         e = strchr(cid_start, ':');
@@ -1557,6 +1564,7 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
                         .svm_family = AF_VSOCK,
                         .svm_port = port,
                 },
+                .type = type,
                 .size = sizeof(struct sockaddr_vm),
         };
 
index b323b1b99f57d02e5b5014ed34016ee0ca0f20e0..37763446bd9a3c48a507e148d9618df4f17c8492 100644 (file)
@@ -354,3 +354,10 @@ int connect_unix_path(int fd, int dir_fd, const char *path);
  * protocol mismatch. */
 int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
 int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
+
+/* libc's SOMAXCONN is defined to 128 or 4096 (at least on glibc). But actually, the value can be much
+ * larger. In our codebase we want to set it to the max usually, since noawadays socket memory is properly
+ * tracked by memcg, and hence we don't need to enforce extra limits here. Moreover, the kernel caps it to
+ * /proc/sys/net/core/somaxconn anyway, thus by setting this to unbounded we just make that sysctl file
+ * authoritative. */
+#define SOMAXCONN_DELUXE INT_MAX
index 633d9479dd2a6aa5ac9fbbd9907c60fcc44c21a4..3c999098e15e60aceb670b3036cab55f8d809863 100644 (file)
@@ -207,20 +207,13 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
         return F_TYPE_EQUAL(s->f_type, magic_value);
 }
 
-int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
-        struct statfs s;
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        return is_fs_type(&s, magic_value);
-}
-
-int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
+int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
         struct statfs s;
+        int r;
 
-        if (statfs(path, &s) < 0)
-                return -errno;
+        r = xstatfsat(dir_fd, path, &s);
+        if (r < 0)
+                return r;
 
         return is_fs_type(&s, magic_value);
 }
@@ -461,7 +454,6 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
         _cleanup_close_ int fd = -EBADF;
 
         assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
-        assert(path);
         assert(ret);
 
         fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
index 3ae8b3eeb1bffaa9ba88b0e9232c64d09746766c..ae0aaf8f512a4051e482aef0233c61dd3649cfa4 100644 (file)
@@ -48,8 +48,13 @@ static inline int inode_same(const char *filea, const char *fileb, int flags) {
 typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
 
 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
-int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
-int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
+int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value);
+static inline int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
+        return is_fs_type_at(fd, NULL, magic_value);
+}
+static inline int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
+        return is_fs_type_at(AT_FDCWD, path, magic_value);
+}
 
 bool is_temporary_fs(const struct statfs *s) _pure_;
 bool is_network_fs(const struct statfs *s) _pure_;
index f124e6f016203ea0eb541c5d79b3ff78313b49bf..b3ade93122a3ec28c3d816afe9a88a3e80f2fb9b 100644 (file)
@@ -327,7 +327,7 @@ char *format_timestamp_style(
                 if (l < (size_t) (1 + 1 + 1))
                         return NULL; /* not enough space for even the shortest of forms */
 
-                return snprintf_ok(buf, l, "@" USEC_FMT, t / USEC_PER_SEC);  /* round down µs → s */
+                return snprintf_ok(buf, l, "@" USEC_FMT, t / USEC_PER_SEC);  /* round down μs → s */
         }
 
         utc = IN_SET(style, TIMESTAMP_UTC, TIMESTAMP_US_UTC, TIMESTAMP_DATE);
@@ -1046,7 +1046,8 @@ static const char* extract_multiplier(const char *p, usec_t *ret) {
                 { "y",       USEC_PER_YEAR   },
                 { "usec",    1ULL            },
                 { "us",      1ULL            },
-                { "µs",      1ULL            },
+                { "μs",      1ULL            }, /* U+03bc (aka GREEK SMALL LETTER MU) */
+                { "µs",      1ULL            }, /* U+b5 (aka MICRO SIGN) */
         };
 
         assert(p);
@@ -1224,7 +1225,8 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *ret) {
                 { "y",       NSEC_PER_YEAR   },
                 { "usec",    NSEC_PER_USEC   },
                 { "us",      NSEC_PER_USEC   },
-                { "µs",      NSEC_PER_USEC   },
+                { "μs",      NSEC_PER_USEC   }, /* U+03bc (aka GREEK LETTER MU) */
+                { "µs",      NSEC_PER_USEC   }, /* U+b5 (aka MICRO SIGN) */
                 { "nsec",    1ULL            },
                 { "ns",      1ULL            },
                 { "",        1ULL            }, /* default is nsec */
@@ -1701,9 +1703,9 @@ TimestampStyle timestamp_style_from_string(const char *s) {
         t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
         if (t >= 0)
                 return t;
-        if (streq_ptr(s, "µs"))
+        if (STRPTR_IN_SET(s, "µs", "μs")) /* acccept both µ symbols in unicode, i.e. micro symbol + greek small letter mu. */
                 return TIMESTAMP_US;
-        if (streq_ptr(s, "µs+utc"))
+        if (STRPTR_IN_SET(s, "µs+utc", "μs+utc"))
                 return TIMESTAMP_US_UTC;
         return t;
 }
index d44464dd7bd16fce94235551a4987a625fed72bd..e77ca9424892d7a113b258c388a04edabfa9282e 100644 (file)
@@ -17,6 +17,7 @@
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "sync-util.h"
 #include "tmpfile-util.h"
 #include "umask-util.h"
 
@@ -349,7 +350,7 @@ static int link_fd(int fd, int newdirfd, const char *newpath) {
         return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
 }
 
-int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, bool replace) {
+int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags) {
         _cleanup_free_ char *tmp = NULL;
         int r;
 
@@ -361,40 +362,52 @@ int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, bo
          * an fd created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE
          * is not supported on the directory, and renameat2() is used instead. */
 
+        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC) && fsync(fd) < 0)
+                return -errno;
+
         if (path) {
-                if (replace)
-                        return RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+                if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+                        r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
+                else
+                        r = rename_noreplace(dir_fd, path, dir_fd, target);
+                if (r < 0)
+                        return r;
+        } else {
 
-                return rename_noreplace(dir_fd, path, dir_fd, target);
-        }
+                r = link_fd(fd, dir_fd, target);
+                if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+                        return r;
 
-        r = link_fd(fd, dir_fd, target);
-        if (r != -EEXIST || !replace)
-                return r;
+                /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
+                 * linkat() logic does not allow that. We work-around this by linking the file to a random name
+                 * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
+                 * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
+                 * system under a temporary name) is very short. */
 
-        /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
-         * linkat() logic does not allow that. We work-around this by linking the file to a random name
-         * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
-         * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
-         * system under a temporary name) is very short. */
+                r = tempfn_random(target, NULL, &tmp);
+                if (r < 0)
+                        return r;
 
-        r = tempfn_random(target, NULL, &tmp);
-        if (r < 0)
-                return r;
+                if (link_fd(fd, dir_fd, tmp) < 0)
+                        return -EEXIST; /* propagate original error */
 
-        if (link_fd(fd, dir_fd, tmp) < 0)
-                return -EEXIST; /* propagate original error */
+                r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
+                if (r < 0) {
+                        (void) unlinkat(dir_fd, tmp, 0);
+                        return r;
+                }
+        }
 
-        r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
-        if (r < 0) {
-                (void) unlinkat(dir_fd, tmp, 0);
-                return r;
+        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
+                r = fsync_full(fd);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
 }
 
-int flink_tmpfile(FILE *f, const char *path, const char *target, bool replace) {
+int flink_tmpfile(FILE *f, const char *path, const char *target, LinkTmpfileFlags flags) {
         int fd, r;
 
         assert(f);
@@ -404,11 +417,11 @@ int flink_tmpfile(FILE *f, const char *path, const char *target, bool replace) {
         if (fd < 0) /* Not all FILE* objects encapsulate fds */
                 return -EBADF;
 
-        r = fflush_sync_and_check(f);
+        r = fflush_and_check(f);
         if (r < 0)
                 return r;
 
-        return link_tmpfile(fd, path, target, replace);
+        return link_tmpfile(fd, path, target, flags);
 }
 
 int mkdtemp_malloc(const char *template, char **ret) {
index f48ce10e688207fc6b71fe0749c069d3a01ae517..50904ecac104c94a400a10cc39ebe1b1f9208963 100644 (file)
@@ -29,11 +29,17 @@ static inline int open_tmpfile_linkable(const char *target, int flags, char **re
 }
 int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file);
 
-int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, bool replace);
-static inline int link_tmpfile(int fd, const char *path, const char *target, bool replace) {
-        return link_tmpfile_at(fd, AT_FDCWD, path, target, replace);
+
+typedef enum LinkTmpfileFlags {
+        LINK_TMPFILE_REPLACE = 1 << 0,
+        LINK_TMPFILE_SYNC    = 1 << 1,
+} LinkTmpfileFlags;
+
+int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags);
+static inline int link_tmpfile(int fd, const char *path, const char *target, LinkTmpfileFlags flags) {
+        return link_tmpfile_at(fd, AT_FDCWD, path, target, flags);
 }
-int flink_tmpfile(FILE *f, const char *path, const char *target, bool replace);
+int flink_tmpfile(FILE *f, const char *path, const char *target, LinkTmpfileFlags flags);
 
 int mkdtemp_malloc(const char *template, char **ret);
 int mkdtemp_open(const char *template, int flags, char **ret);
similarity index 94%
rename from src/shared/uid-alloc-range.c
rename to src/basic/uid-alloc-range.c
index fe7f158c41e4d8cde42ff083679d17589389a19a..669cb6d56f7be263dc712ab8732b068e95881c17 100644 (file)
@@ -122,3 +122,10 @@ bool gid_is_system(gid_t gid) {
 
         return gid <= defs->system_gid_max;
 }
+
+bool uid_for_system_journal(uid_t uid) {
+
+        /* Returns true if the specified UID shall get its data stored in the system journal. */
+
+        return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY || uid_is_container(uid);
+}
similarity index 95%
rename from src/shared/uid-alloc-range.h
rename to src/basic/uid-alloc-range.h
index d3bf077045fa32f62e946570284d886a8e151378..5badde148a564daf3dee56d4f31bc3b16c84ce7e 100644 (file)
@@ -32,3 +32,5 @@ typedef struct UGIDAllocationRange {
 
 int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root);
 const UGIDAllocationRange *acquire_ugid_allocation_range(void);
+
+bool uid_for_system_journal(uid_t uid);
index 2dd50360ecd471a21a1600fcf566a6a39e252f7e..397db7d3a2eeccbffb773bf39fea44f06c0b3de4 100644 (file)
@@ -454,7 +454,7 @@ static int install_loader_config(const char *esp_path) {
                 fprintf(f, "default %s-*\n", arg_entry_token);
         }
 
-        r = flink_tmpfile(f, t, p, /* replace= */ false);
+        r = flink_tmpfile(f, t, p, LINK_TMPFILE_SYNC);
         if (r == -EEXIST)
                 return 0; /* Silently skip creation if the file exists now (recheck) */
         if (r < 0)
@@ -483,7 +483,7 @@ static int install_loader_specification(const char *root) {
 
         fprintf(f, "type1\n");
 
-        r = flink_tmpfile(f, t, p, /* replace= */ false);
+        r = flink_tmpfile(f, t, p, LINK_TMPFILE_SYNC);
         if (r == -EEXIST)
                 return 0; /* Silently skip creation if the file exists now (recheck) */
         if (r < 0)
index da55ad8e0d5e53f27fe40827d4b8a8ec427daf70..36ca830f8a3c44923bb39cac548e38118f5759b9 100644 (file)
@@ -159,7 +159,8 @@ static int help(int argc, char *argv[], void *userdata) {
                "  update               Update systemd-boot in the ESP and EFI variables\n"
                "  remove               Remove systemd-boot from the ESP and EFI variables\n"
                "  is-installed         Test whether systemd-boot is installed in the ESP\n"
-               "  random-seed          Initialize random seed in ESP and EFI variables\n"
+               "  random-seed          Initialize or refresh random seed in ESP and EFI\n"
+               "                       variables\n"
                "\n%3$sKernel Image Commands:%4$s\n"
                "  kernel-identify      Identify kernel image type\n"
                "  kernel-inspect       Prints details about the kernel image\n"
index 67f4a5ea620e2e48d9e4077abb5c0b09a23d3dc6..cda6f5642681a38e89070058120988c806c41bed 100644 (file)
@@ -2421,7 +2421,9 @@ static void config_free(Config *config) {
                 config_entry_free(config->entries[i]);
         free(config->entries);
         free(config->entry_default_config);
+        free(config->entry_default_efivar);
         free(config->entry_oneshot);
+        free(config->entry_saved);
 }
 
 static void config_write_entries_to_variable(Config *config) {
@@ -2645,13 +2647,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
          * By default, Shim uninstalls its protocol when calling StartImage(). */
         shim_retain_protocol();
 
-        err = BS->OpenProtocol(
-                        image,
-                        MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
-                        (void **) &loaded_image,
-                        image,
-                        NULL,
-                        EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+        err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
         if (err != EFI_SUCCESS)
                 return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
 
@@ -2667,10 +2663,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
 
         config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
 
-        if (config.entry_count == 0) {
-                log_error("No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
-                goto out;
-        }
+        if (config.entry_count == 0)
+                return log_error_status(
+                                EFI_NOT_FOUND,
+                                "No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
 
         /* select entry or show menu when key is pressed or timeout is set */
         if (config.force_menu || config.timeout_sec > 0)
@@ -2697,7 +2693,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 if (menu) {
                         efivar_set_time_usec(MAKE_GUID_PTR(LOADER), u"LoaderTimeMenuUSec", 0);
                         if (!menu_run(&config, &entry, loaded_image_path))
-                                break;
+                                return EFI_SUCCESS;
                 }
 
                 /* if auto enrollment is activated, we try to load keys for the given entry. */
@@ -2723,15 +2719,11 @@ static EFI_STATUS run(EFI_HANDLE image) {
 
                 err = image_start(image, entry);
                 if (err != EFI_SUCCESS)
-                        goto out;
+                        return err;
 
                 menu = true;
                 config.timeout_sec = 0;
         }
-        err = EFI_SUCCESS;
-out:
-        BS->CloseProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), image, NULL);
-        return err;
 }
 
 DEFINE_EFI_MAIN_FUNCTION(run, "systemd-boot", /*wait_for_debugger=*/false);
index e8af9995086ea78f15bb9aace04ee8d9317fccc6..527b05f5dbd39d37a6174412c3e8b21baae429ba 100644 (file)
@@ -117,19 +117,10 @@ EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) {
                 return EFI_SUCCESS;
 
         /* get the LoadFile2 protocol that we allocated earlier */
-        err = BS->OpenProtocol(
-                        initrd_handle,
-                        MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL),
-                        (void **) &loader,
-                        NULL,
-                        NULL,
-                        EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+        err = BS->HandleProtocol(initrd_handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), (void **) &loader);
         if (err != EFI_SUCCESS)
                 return err;
 
-        /* close the handle */
-        (void) BS->CloseProtocol(initrd_handle, MAKE_GUID_PTR(EFI_LOAD_FILE2_PROTOCOL), NULL, NULL);
-
         /* uninstall all protocols thus destroying the handle */
         err = BS->UninstallMultipleProtocolInterfaces(
                         initrd_handle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL),
index c315a4d51aef17d8792953871eddb3a9da7557b3..93a364142433e6874febdf4f4c0d49f468509997 100644 (file)
@@ -379,13 +379,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
         uint64_t loader_features = 0;
         EFI_STATUS err;
 
-        err = BS->OpenProtocol(
-                        image,
-                        MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
-                        (void **) &loaded_image,
-                        image,
-                        NULL,
-                        EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+        err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
         if (err != EFI_SUCCESS)
                 return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
 
index 98db82696c2ca0fb4f8c7573b0270fc759bba9e5..fefb509ffd4ec472c9152b3cf8c95467f5305dd1 100644 (file)
@@ -341,7 +341,7 @@ static int run(int argc, char *argv[]) {
                 return EXIT_SUCCESS;
         }
 
-        _cleanup_tpm2_context_ Tpm2Context *c = NULL;
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
         r = tpm2_context_new(arg_tpm2_device, &c);
         if (r < 0)
                 return r;
index a34b0aa604b0da2d2d8dbc873afefa744e4a1feb..70fa260246929ea1e66b6a0b8b9869c63ca25b40 100644 (file)
@@ -185,7 +185,7 @@ static void show_cg_info(const char *controller, const char *path) {
         if (cg_all_unified() == 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
                 printf("Controller %s; ", controller);
 
-        printf("Control group %s:\n", empty_to_root(path));
+        printf("CGroup %s:\n", empty_to_root(path));
         fflush(stdout);
 }
 
index bb4f7a5ef0997742a91e7fb3828402d189761897..987643f661724f63459f76ea8eeeb242671a7cc7 100644 (file)
@@ -647,7 +647,7 @@ static void display(Hashmap *a) {
 
                 printf("%s%s%-*s%s %s%7s%s %s%*s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
                        ansi_underline(),
-                       arg_order == ORDER_PATH ? on : "", path_columns, "Control Group",
+                       arg_order == ORDER_PATH ? on : "", path_columns, "CGroup",
                        arg_order == ORDER_PATH ? off : "",
                        arg_order == ORDER_TASKS ? on : "",
                        arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
index 839b1676c88a29b5f5fde28a71b77cafa9a8ee6e..34643b242ceae61ee3fd21003a1f022580ad09a9 100644 (file)
@@ -3319,6 +3319,8 @@ static int on_cgroup_oom_event(sd_event_source *s, void *userdata) {
         }
 
         (void) unit_check_oom(u);
+        unit_add_to_gc_queue(u);
+
         return 0;
 }
 
index 726035b00a3aebf25eb554a88961cda785aa9066..59d7a3ba71fe0a0896921162db930d5fee46adf9 100644 (file)
@@ -7,6 +7,7 @@
 #include "bpf-firewall.h"
 #include "bpf-foreign.h"
 #include "bus-get-properties.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
 #include "core-varlink.h"
@@ -400,9 +401,9 @@ static int property_get_restrict_network_interfaces(
                 sd_bus_message *reply,
                 void *userdata,
                 sd_bus_error *error) {
-        int r;
+
         CGroupContext *c = ASSERT_PTR(userdata);
-        char *iface;
+        int r;
 
         assert(bus);
         assert(reply);
@@ -415,17 +416,7 @@ static int property_get_restrict_network_interfaces(
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_open_container(reply, 'a', "s");
-        if (r < 0)
-                return r;
-
-        SET_FOREACH(iface, c->restrict_network_interfaces) {
-                r = sd_bus_message_append(reply, "s", iface);
-                if (r < 0)
-                        return r;
-        }
-
-        r = sd_bus_message_close_container(reply);
+        r = bus_message_append_string_set(reply, c->restrict_network_interfaces);
         if (r < 0)
                 return r;
 
index fb22a9769d8acc2336ab80c9a43c88a3241a94d9..04070a7f1efb7519ca7fe83c7d6ade7ae81ff3e3 100644 (file)
@@ -10,6 +10,7 @@
 #include "af-list.h"
 #include "alloc-util.h"
 #include "bus-get-properties.h"
+#include "bus-util.h"
 #include "cap-list.h"
 #include "capability-util.h"
 #include "cpu-set-util.h"
@@ -26,6 +27,7 @@
 #include "io-util.h"
 #include "ioprio-util.h"
 #include "journal-file.h"
+#include "load-fragment.h"
 #include "memstream-util.h"
 #include "missing_ioprio.h"
 #include "mountpoint-util.h"
@@ -1281,6 +1283,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("SetCredentialEncrypted", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("LoadCredential", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("LoadCredentialEncrypted", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ImportCredential", "as", bus_property_get_string_set, offsetof(ExecContext, import_credentials), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -2311,41 +2314,54 @@ int bus_exec_context_set_transient_property(
                         isempty = false;
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                                _cleanup_free_ char *copy = NULL;
-                                ExecLoadCredential *old;
+                                bool encrypted = streq(name, "LoadCredentialEncrypted");
 
-                                copy = strdup(source);
-                                if (!copy)
-                                        return -ENOMEM;
+                                r = hashmap_put_credential(&c->load_credentials, id, source, encrypted);
+                                if (r < 0)
+                                        return r;
 
-                                old = hashmap_get(c->load_credentials, id);
-                                if (old) {
-                                        free_and_replace(old->path, copy);
-                                        old->encrypted = streq(name, "LoadCredentialEncrypted");
-                                } else {
-                                        _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+                                (void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s:%s", name, id, source);
+                        }
+                }
 
-                                        lc = new(ExecLoadCredential, 1);
-                                        if (!lc)
-                                                return -ENOMEM;
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
 
-                                        *lc = (ExecLoadCredential) {
-                                                .id = strdup(id),
-                                                .path = TAKE_PTR(copy),
-                                                .encrypted = streq(name, "LoadCredentialEncrypted"),
-                                        };
+                if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
+                        c->load_credentials = hashmap_free(c->load_credentials);
+                        (void) unit_write_settingf(u, flags, name, "%s=", name);
+                }
 
-                                        if (!lc->id)
-                                                return -ENOMEM;
+                return 1;
 
-                                        r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
-                                        if (r < 0)
-                                                return r;
+        } else if (streq(name, "ImportCredential")) {
+                bool isempty = true;
 
-                                        TAKE_PTR(lc);
-                                }
+                r = sd_bus_message_enter_container(message, 'a', "s");
+                if (r < 0)
+                        return r;
 
-                                (void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s:%s", name, id, source);
+                for (;;) {
+                        const char *s;
+
+                        r = sd_bus_message_read(message, "s", &s);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                break;
+
+                        if (!filename_is_valid(s))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential name is invalid: %s", s);
+
+                        isempty = false;
+
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                r = set_put_strdup(&c->import_credentials, s);
+                                if (r < 0)
+                                        return r;
+
+                                (void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, s);
                         }
                 }
 
@@ -2354,7 +2370,7 @@ int bus_exec_context_set_transient_property(
                         return r;
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
-                        c->load_credentials = hashmap_free(c->load_credentials);
+                        c->import_credentials = set_free(c->import_credentials);
                         (void) unit_write_settingf(u, flags, name, "%s=", name);
                 }
 
index 9792a5c44a1891d34d6c742b862da433cd5ece44..c88d8c2dd5fc3eec11be3581095302df5c120b2e 100644 (file)
@@ -241,6 +241,9 @@ void bus_job_send_change_signal(Job *j) {
         if (j->in_dbus_queue) {
                 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
                 j->in_dbus_queue = false;
+
+                /* The job might be good to be GC once its pending signals have been sent */
+                job_add_to_gc_queue(j);
         }
 
         r = bus_foreach_bus(j->manager, j->bus_track, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
index 59d541ebfe61ecd18a89d1946e52082e6fe48512..629f08ebcc6c04e098d94b9b49001664e2d2afeb 100644 (file)
@@ -1648,6 +1648,9 @@ void bus_unit_send_change_signal(Unit *u) {
         if (u->in_dbus_queue) {
                 LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
                 u->in_dbus_queue = false;
+
+                /* The unit might be good to be GC once its pending signals have been sent */
+                unit_add_to_gc_queue(u);
         }
 
         if (!u->id)
index 3fef44e6687575adf9a26d616017c216a7c4c99b..ba2cec4d7718ad3299108ab2d865f8d8f4665e51 100644 (file)
@@ -972,7 +972,7 @@ int bus_init_private(Manager *m) {
         if (r < 0)
                 return log_error_errno(errno, "Failed to bind private socket: %m");
 
-        r = listen(fd, SOMAXCONN);
+        r = listen(fd, SOMAXCONN_DELUXE);
         if (r < 0)
                 return log_error_errno(errno, "Failed to make private socket listening: %m");
 
index 1802ae05b30db4e6e9e891c47606f3d33709ca73..f9a8ae9f154abce6f83a9a2cb7bac6142babce04 100644 (file)
@@ -1544,7 +1544,8 @@ bool exec_context_has_credentials(const ExecContext *context) {
         assert(context);
 
         return !hashmap_isempty(context->set_credentials) ||
-                !hashmap_isempty(context->load_credentials);
+                !hashmap_isempty(context->load_credentials) ||
+                !set_isempty(context->import_credentials);
 }
 
 #if HAVE_SECCOMP
@@ -2757,19 +2758,26 @@ static int write_credential(
         return 0;
 }
 
-static char **credential_search_path(
-                const ExecParameters *params,
-                bool encrypted) {
+typedef enum CredentialSearchPath {
+        CREDENTIAL_SEARCH_PATH_TRUSTED,
+        CREDENTIAL_SEARCH_PATH_ENCRYPTED,
+        CREDENTIAL_SEARCH_PATH_ALL,
+        _CREDENTIAL_SEARCH_PATH_MAX,
+        _CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL,
+} CredentialSearchPath;
+
+static char **credential_search_path(const ExecParameters *params, CredentialSearchPath path) {
 
         _cleanup_strv_free_ char **l = NULL;
 
         assert(params);
+        assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX);
 
-        /* Assemble a search path to find credentials in. We'll look in /etc/credstore/ (and similar
-         * directories in /usr/lib/ + /run/) for all types of credentials. If we are looking for encrypted
-         * credentials, also look in /etc/credstore.encrypted/ (and similar dirs). */
+        /* Assemble a search path to find credentials in. For non-encrypted credentials, We'll look in
+         * /etc/credstore/ (and similar directories in /usr/lib/ + /run/). If we're looking for encrypted
+         * credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */
 
-        if (encrypted) {
+        if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) {
                 if (strv_extend(&l, params->received_encrypted_credentials_directory) < 0)
                         return NULL;
 
@@ -2777,12 +2785,14 @@ static char **credential_search_path(
                         return NULL;
         }
 
-        if (params->received_credentials_directory)
-                if (strv_extend(&l, params->received_credentials_directory) < 0)
-                        return NULL;
+        if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) {
+                if (params->received_credentials_directory)
+                        if (strv_extend(&l, params->received_credentials_directory) < 0)
+                                return NULL;
 
-        if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0)
-                return NULL;
+                if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0)
+                        return NULL;
+        }
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *t = strv_join(l, ":");
@@ -2793,6 +2803,111 @@ static char **credential_search_path(
         return TAKE_PTR(l);
 }
 
+static int maybe_decrypt_and_write_credential(
+                int dir_fd,
+                const char *id,
+                bool encrypted,
+                uid_t uid,
+                bool ownership_ok,
+                const char *data,
+                size_t size,
+                uint64_t *left) {
+
+        _cleanup_free_ void *plaintext = NULL;
+        size_t add;
+        int r;
+
+        if (encrypted) {
+                size_t plaintext_size = 0;
+
+                r = decrypt_credential_and_warn(id, now(CLOCK_REALTIME), NULL, NULL, data, size,
+                                                &plaintext, &plaintext_size);
+                if (r < 0)
+                        return r;
+
+                data = plaintext;
+                size = plaintext_size;
+        }
+
+        add = strlen(id) + size;
+        if (add > *left)
+                return -E2BIG;
+
+        r = write_credential(dir_fd, id, data, size, uid, ownership_ok);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to write credential '%s': %m", id);
+
+        *left -= add;
+        return 0;
+}
+
+static int load_credential_glob(
+                const char *path,
+                bool encrypted,
+                char **search_path,
+                ReadFullFileFlags flags,
+                int write_dfd,
+                uid_t uid,
+                bool ownership_ok,
+                uint64_t *left) {
+
+        int r;
+
+        STRV_FOREACH(d, search_path) {
+                _cleanup_globfree_ glob_t pglob = {};
+                _cleanup_free_ char *j = NULL;
+
+                j = path_join(*d, path);
+                if (!j)
+                        return -ENOMEM;
+
+                r = safe_glob(j, 0, &pglob);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+
+                for (size_t n = 0; n < pglob.gl_pathc; n++) {
+                        _cleanup_free_ char *fn = NULL;
+                        _cleanup_(erase_and_freep) char *data = NULL;
+                        size_t size;
+
+                        /* path is absolute, hence pass AT_FDCWD as nop dir fd here */
+                        r = read_full_file_full(
+                                AT_FDCWD,
+                                pglob.gl_pathv[n],
+                                UINT64_MAX,
+                                encrypted ? CREDENTIAL_ENCRYPTED_SIZE_MAX : CREDENTIAL_SIZE_MAX,
+                                flags,
+                                NULL,
+                                &data, &size);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to read credential '%s': %m",
+                                                        pglob.gl_pathv[n]);
+
+                        r = path_extract_filename(pglob.gl_pathv[n], &fn);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to extract filename from '%s': %m",
+                                                        pglob.gl_pathv[n]);
+
+                        r = maybe_decrypt_and_write_credential(
+                                write_dfd,
+                                fn,
+                                encrypted,
+                                uid,
+                                ownership_ok,
+                                data, size,
+                                left);
+                        if (r == -EEXIST)
+                                continue;
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
 static int load_credential(
                 const ExecContext *context,
                 const ExecParameters *params,
@@ -2812,7 +2927,7 @@ static int load_credential(
         _cleanup_free_ char *bindname = NULL;
         const char *source = NULL;
         bool missing_ok = true;
-        size_t size, add, maxsz;
+        size_t size, maxsz;
         int r;
 
         assert(context);
@@ -2858,7 +2973,7 @@ static int load_credential(
                  * directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we
                  * are operating on a credential store, i.e. this is guaranteed to be regular files. */
 
-                search_path = credential_search_path(params, encrypted);
+                search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ALL);
                 if (!search_path)
                         return -ENOMEM;
 
@@ -2914,28 +3029,7 @@ static int load_credential(
         if (r < 0)
                 return log_debug_errno(r, "Failed to read credential '%s': %m", path);
 
-        if (encrypted) {
-                _cleanup_free_ void *plaintext = NULL;
-                size_t plaintext_size = 0;
-
-                r = decrypt_credential_and_warn(id, now(CLOCK_REALTIME), NULL, NULL, data, size, &plaintext, &plaintext_size);
-                if (r < 0)
-                        return r;
-
-                free_and_replace(data, plaintext);
-                size = plaintext_size;
-        }
-
-        add = strlen(id) + size;
-        if (add > *left)
-                return -E2BIG;
-
-        r = write_credential(write_dfd, id, data, size, uid, ownership_ok);
-        if (r < 0)
-                return log_debug_errno(r, "Failed to write credential '%s': %m", id);
-
-        *left -= add;
-        return 0;
+        return maybe_decrypt_and_write_credential(write_dfd, id, encrypted, uid, ownership_ok, data, size, left);
 }
 
 struct load_cred_args {
@@ -3010,6 +3104,7 @@ static int acquire_credentials(
 
         uint64_t left = CREDENTIALS_TOTAL_SIZE_MAX;
         _cleanup_close_ int dfd = -EBADF;
+        const char *ic;
         ExecLoadCredential *lc;
         ExecSetCredential *sc;
         int r;
@@ -3075,8 +3170,47 @@ static int acquire_credentials(
                         return r;
         }
 
-        /* Second, we add in literally specified credentials. If the credentials already exist, we'll not add
-         * them, so that they can act as a "default" if the same credential is specified multiple times. */
+        /* Next, look for system credentials and credentials in the credentials store. Note that these do not
+         * override any credentials found earlier. */
+        SET_FOREACH(ic, context->import_credentials) {
+                _cleanup_free_ char **search_path = NULL;
+
+                search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED);
+                if (!search_path)
+                        return -ENOMEM;
+
+                r = load_credential_glob(
+                                ic,
+                                /* encrypted = */ false,
+                                search_path,
+                                READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER,
+                                dfd,
+                                uid,
+                                ownership_ok,
+                                &left);
+                if (r < 0)
+                        return r;
+
+                search_path = strv_free(search_path);
+                search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED);
+                if (!search_path)
+                        return -ENOMEM;
+
+                r = load_credential_glob(
+                                ic,
+                                /* encrypted = */ true,
+                                search_path,
+                                READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER|READ_FULL_FILE_UNBASE64,
+                                dfd,
+                                uid,
+                                ownership_ok,
+                                &left);
+                if (r < 0)
+                        return r;
+        }
+
+        /* Finally, we add in literally specified credentials. If the credentials already exist, we'll not
+         * add them, so that they can act as a "default" if the same credential is specified multiple times. */
         HASHMAP_FOREACH(sc, context->set_credentials) {
                 _cleanup_(erase_and_freep) void *plaintext = NULL;
                 const char *data;
@@ -5874,6 +6008,7 @@ void exec_context_done(ExecContext *c) {
 
         c->load_credentials = hashmap_free(c->load_credentials);
         c->set_credentials = hashmap_free(c->set_credentials);
+        c->import_credentials = set_free(c->import_credentials);
 
         c->root_image_policy = image_policy_free(c->root_image_policy);
         c->mount_image_policy = image_policy_free(c->mount_image_policy);
@@ -6118,7 +6253,7 @@ static int exec_context_load_environment(const Unit *unit, const ExecContext *c,
                 /* When we don't match anything, -ENOENT should be returned */
                 assert(pglob.gl_pathc > 0);
 
-                for (unsigned n = 0; n < pglob.gl_pathc; n++) {
+                for (size_t n = 0; n < pglob.gl_pathc; n++) {
                         _cleanup_strv_free_ char **p = NULL;
 
                         r = load_env_file(NULL, pglob.gl_pathv[n], &p);
index 1c8378c8b09de94e552978f46a498f7acaedf94c..953dc9e7f778aef9cac7f5f4faaf047619eb4159 100644 (file)
@@ -361,6 +361,7 @@ struct ExecContext {
 
         Hashmap *set_credentials; /* output id → ExecSetCredential */
         Hashmap *load_credentials; /* output id → ExecLoadCredential */
+        Set *import_credentials;
 
         ImagePolicy *root_image_policy, *mount_image_policy, *extension_image_policy;
 };
index f87b0f7c7471bc5fcb8ca963e4f925be6f184fee..50f9581d727cd5657b851bf73dac99f4ffada2b5 100644 (file)
@@ -1444,6 +1444,10 @@ bool job_may_gc(Job *j) {
         if (!UNIT_VTABLE(j->unit)->gc_jobs)
                 return false;
 
+        /* Make sure to send out pending D-Bus events before we unload the unit */
+        if (j->in_dbus_queue)
+                return false;
+
         if (sd_bus_track_count(j->bus_track) > 0)
                 return false;
 
index 64a00fef28d8a7984f84f4b0ec21c7a47d583001..ae318dae895a3a4c60d32bd9b86ec888cf1a0eb4 100644 (file)
 {{type}}.SetCredentialEncrypted,           config_parse_set_credential,                 1,                                  offsetof({{type}}, exec_context)
 {{type}}.LoadCredential,                   config_parse_load_credential,                0,                                  offsetof({{type}}, exec_context)
 {{type}}.LoadCredentialEncrypted,          config_parse_load_credential,                1,                                  offsetof({{type}}, exec_context)
+{{type}}.ImportCredential,                 config_parse_import_credential,              0,                                  offsetof({{type}}, exec_context.import_credentials)
 {{type}}.TimeoutCleanSec,                  config_parse_sec,                            0,                                  offsetof({{type}}, exec_context.timeout_clean_usec)
 {% if HAVE_PAM %}
 {{type}}.PAMName,                          config_parse_unit_string_printf,             0,                                  offsetof({{type}}, exec_context.pam_name)
index 554180f1e3152360c11d1f1b6a2ce59a37866cec..6d129af7b2aec4f1139970d8fcac87c2179be9ce 100644 (file)
@@ -4840,6 +4840,46 @@ int config_parse_set_credential(
         return 0;
 }
 
+int hashmap_put_credential(Hashmap **h, const char *id, const char *path, bool encrypted) {
+        ExecLoadCredential *old;
+        int r;
+
+        assert(h);
+        assert(id);
+        assert(path);
+
+        old = hashmap_get(*h, id);
+        if (old) {
+                r = free_and_strdup(&old->path, path);
+                if (r < 0)
+                        return r;
+
+                old->encrypted = encrypted;
+        } else {
+                _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+
+                lc = new(ExecLoadCredential, 1);
+                if (!lc)
+                        return log_oom();
+
+                *lc = (ExecLoadCredential) {
+                        .id = strdup(id),
+                        .path = strdup(path),
+                        .encrypted = encrypted,
+                };
+                if (!lc->id || !lc->path)
+                        return -ENOMEM;
+
+                r = hashmap_ensure_put(h, &exec_load_credential_hash_ops, lc->id, lc);
+                if (r < 0)
+                        return r;
+
+                TAKE_PTR(lc);
+        }
+
+        return 0;
+}
+
 int config_parse_load_credential(
                 const char *unit,
                 const char *filename,
@@ -4854,7 +4894,6 @@ int config_parse_load_credential(
 
         _cleanup_free_ char *word = NULL, *k = NULL, *q = NULL;
         ExecContext *context = ASSERT_PTR(data);
-        ExecLoadCredential *old;
         bool encrypted = ltype;
         Unit *u = userdata;
         const char *p;
@@ -4907,35 +4946,54 @@ int config_parse_load_credential(
                 }
         }
 
-        old = hashmap_get(context->load_credentials, k);
-        if (old) {
-                free_and_replace(old->path, q);
-                old->encrypted = encrypted;
-        } else {
-                _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+        r = hashmap_put_credential(&context->load_credentials, k, q, encrypted);
+        if (r < 0)
+                return log_error_errno(r, "Failed to store load credential '%s': %m", rvalue);
 
-                lc = new(ExecLoadCredential, 1);
-                if (!lc)
-                        return log_oom();
+        return 0;
+}
 
-                *lc = (ExecLoadCredential) {
-                        .id = TAKE_PTR(k),
-                        .path = TAKE_PTR(q),
-                        .encrypted = encrypted,
-                };
+int config_parse_import_credential(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
 
-                r = hashmap_ensure_put(&context->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
-                if (r == -ENOMEM)
-                        return log_oom();
-                if (r < 0) {
-                        log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "Duplicated credential value '%s', ignoring assignment: %s", lc->id, rvalue);
-                        return 0;
-                }
+        _cleanup_free_ char *s = NULL;
+        Set** import_credentials = ASSERT_PTR(data);
+        Unit *u = userdata;
+        int r;
 
-                TAKE_PTR(lc);
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                *import_credentials = set_free(*import_credentials);
+                return 0;
+        }
+
+        r = unit_cred_printf(u, rvalue, &s);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
+                return 0;
+        }
+        if (!filename_is_valid(s)) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", s);
+                return 0;
         }
 
+        r = set_put_strdup(import_credentials, s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to store credential name '%s': %m", rvalue);
+
         return 0;
 }
 
index 59f02a32072f24a2adb10d20e5c7e987196aed2d..3cfb50969a91a4404e2a7843636bdd2ced0c8945 100644 (file)
@@ -12,6 +12,8 @@ int unit_is_likely_recursive_template_dependency(Unit *u, const char *name, cons
 int parse_crash_chvt(const char *value, int *data);
 int parse_confirm_spawn(const char *value, char **console);
 
+int hashmap_put_credential(Hashmap **h, const char *id, const char *path, bool encrypted);
+
 /* Read service data from .desktop file style configuration fragments */
 
 int unit_load_fragment(Unit *u);
@@ -105,6 +107,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_preserve_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_exec_directories);
 CONFIG_PARSER_PROTOTYPE(config_parse_set_credential);
 CONFIG_PARSER_PROTOTYPE(config_parse_load_credential);
+CONFIG_PARSER_PROTOTYPE(config_parse_import_credential);
 CONFIG_PARSER_PROTOTYPE(config_parse_set_status);
 CONFIG_PARSER_PROTOTYPE(config_parse_namespace_path_strv);
 CONFIG_PARSER_PROTOTYPE(config_parse_temporary_filesystems);
index 152b5d4c5d227478c821291480411c4d9fb31452..91477afc9cf16b00d0e6adbd645ce6043b77b8fa 100644 (file)
@@ -144,7 +144,6 @@ systemd_sources = files(
 
 in_files = [['system.conf',                     pkgsysconfdir],
             ['user.conf',                       pkgsysconfdir],
-            ['systemd.pc',                      pkgconfigdatadir],
             ['org.freedesktop.systemd1.policy', polkitpolicydir]]
 
 foreach item : in_files
@@ -160,6 +159,15 @@ foreach item : in_files
                 install_dir : dir)
 endforeach
 
+systemd_pc = custom_target(
+        'systemd.pc',
+        input : 'systemd.pc.in',
+        output : 'systemd.pc',
+        command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
+        install : pkgconfigdatadir != 'no',
+        install_tag : 'devel',
+        install_dir : pkgconfigdatadir)
+
 install_data('org.freedesktop.systemd1.conf',
              install_dir : dbuspolicydir)
 install_data('org.freedesktop.systemd1.service',
index f8fe62c9191f72056bfdcb64b54f9c31a11f7b3e..e4c1f5a793f903ef80987ca0f8c2da85a1ea601d 100644 (file)
@@ -82,7 +82,7 @@ static void socket_init(Unit *u) {
         assert(u);
         assert(u->load_state == UNIT_STUB);
 
-        s->backlog = SOMAXCONN;
+        s->backlog = SOMAXCONN_DELUXE;
         s->timeout_usec = u->manager->default_timeout_start_usec;
         s->directory_mode = 0755;
         s->socket_mode = 0666;
@@ -3519,7 +3519,7 @@ SocketTimestamping socket_timestamping_from_string_harder(const char *p) {
          * too. */
         if (streq(p, "nsec"))
                 return SOCKET_TIMESTAMPING_NS;
-        if (STR_IN_SET(p, "usec", "µs"))
+        if (STR_IN_SET(p, "usec", "µs", "μs")) /* Accept both small greek letter mu + micro sign unicode codepoints */
                 return SOCKET_TIMESTAMPING_US;
 
         r = parse_boolean(p);
index 7b6d50e0eaf554628091f25d3db91cfe4bce882c..7b2e8c5f5cc2b8fec3a3830cdecd74cee0a0a72f 100644 (file)
@@ -441,7 +441,14 @@ bool unit_may_gc(Unit *u) {
         if (u->perpetual)
                 return false;
 
-        if (u->in_cgroup_empty_queue)
+        /* if we saw a cgroup empty event for this unit, stay around until we processed it so that we remove
+         * the empty cgroup if possible. Similar, process any pending OOM events if they are already queued
+         * before we release the unit. */
+        if (u->in_cgroup_empty_queue || u->in_cgroup_oom_queue)
+                return false;
+
+        /* Make sure to send out D-Bus events before we unload the unit */
+        if (u->in_dbus_queue)
                 return false;
 
         if (sd_bus_track_count(u->bus_track) > 0)
index b355970f0ffa61b27eed8f12dd23280b2d990f27..847ac531dfb018274b442a21c6745672fd8a83cd 100644 (file)
@@ -91,7 +91,7 @@ enum {
         META_ARGV_UID,          /* %u: as seen in the initial user namespace */
         META_ARGV_GID,          /* %g: as seen in the initial user namespace */
         META_ARGV_SIGNAL,       /* %s: number of signal causing dump */
-        META_ARGV_TIMESTAMP,    /* %t: time of dump, expressed as seconds since the Epoch (we expand this to µs granularity) */
+        META_ARGV_TIMESTAMP,    /* %t: time of dump, expressed as seconds since the Epoch (we expand this to μs granularity) */
         META_ARGV_RLIMIT,       /* %c: core file size soft resource limit */
         META_ARGV_HOSTNAME,     /* %h: hostname */
         _META_ARGV_MAX,
@@ -269,11 +269,7 @@ static int fix_permissions(
         (void) fix_acl(fd, uid, allow_user);
         (void) fix_xattr(fd, context);
 
-        r = fsync_full(fd);
-        if (r < 0)
-                return log_error_errno(r, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
-
-        r = link_tmpfile(fd, filename, target, /* replace= */ false);
+        r = link_tmpfile(fd, filename, target, LINK_TMPFILE_SYNC);
         if (r < 0)
                 return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
 
@@ -1209,7 +1205,7 @@ static int gather_pid_metadata_from_argv(
                 case META_ARGV_TIMESTAMP:
                         /* The journal fields contain the timestamp padded with six
                          * zeroes, so that the kernel-supplied 1s granularity timestamps
-                         * becomes 1µs granularity, i.e. the granularity systemd usually
+                         * becomes 1μs granularity, i.e. the granularity systemd usually
                          * operates in. */
                         t = free_timestamp = strjoin(argv[i], "000000");
                         if (!t)
index a22d9323421725ff2521fb1d4b52fff279ab5172..702b2615e29b8ff03c6cf562e1589cadb851edea 100644 (file)
@@ -562,7 +562,8 @@ static int create_disk(
         if (!noauto && !nofail) {
                 r = write_drop_in(arg_dest, dmname, 40, "device-timeout",
                                   "# Automatically generated by systemd-cryptsetup-generator\n\n"
-                                  "[Unit]\nJobTimeoutSec=0");
+                                  "[Unit]\n"
+                                  "JobTimeoutSec=infinity\n");
                 if (r < 0)
                         log_warning_errno(r, "Failed to write device timeout drop-in: %m");
         }
index d58defcc42fa1d33092948825d300161730e4674..31dff24b57e91af794fa252ab45b1002f5ad9c40 100644 (file)
@@ -234,7 +234,7 @@ static int parse_one_option(const char *option) {
                         return log_oom();
 
         } else if ((val = startswith(option, "header="))) {
-                if (!STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT))
+                if (!arg_type || !STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT))
                         arg_type = ANY_LUKS;
 
                 if (!path_is_absolute(val))
@@ -832,7 +832,7 @@ static int measure_volume_key(
         }
 
 #if HAVE_TPM2
-        _cleanup_tpm2_context_ Tpm2Context *c = NULL;
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
         r = tpm2_context_new(arg_tpm2_device, &c);
         if (r < 0)
                 return r;
index 5c742497d5cae6a7eea21b98e280b34ab01c7b67..25bdd68cd20295bef8edaff648bdfe35ca6d4346 100644 (file)
@@ -1286,7 +1286,7 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
                 }
 
                 /* Try to copy as directory? */
-                r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT|COPY_HARDLINKS);
+                r = copy_directory_at(source_fd, NULL, AT_FDCWD, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT|COPY_HARDLINKS);
                 if (r >= 0)
                         return 0;
                 if (r != -ENOTDIR)
index 8036724034f109994a10a208c5a8b61d6595a936..77f51c4245031a07d4cc179c38fbf44f34d2d2ca 100644 (file)
@@ -142,7 +142,7 @@ static int add_cryptsetup(
         r = write_drop_in_format(arg_dest, dmname, 50, "job-timeout",
                                  "# Automatically generated by systemd-gpt-auto-generator\n\n"
                                  "[Unit]\n"
-                                 "JobTimeoutSec=0"); /* the binary handles timeouts anyway */
+                                 "JobTimeoutSec=infinity"); /* the binary handles timeouts anyway */
         if (r < 0)
                 log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
 
index be52c21d00dfbe5adaddb26ed70de215bae00f9c..1bcf9d69df04c0015c0fbf2e147dcfe886941da1 100644 (file)
@@ -95,7 +95,8 @@ static int process_resume(void) {
 
         r = write_drop_in(arg_dest, device_unit, 40, "device-timeout",
                           "# Automatically generated by systemd-hibernate-resume-generator\n\n"
-                          "[Unit]\nJobTimeoutSec=0");
+                          "[Unit]\n"
+                          "JobTimeoutSec=infinity\n");
         if (r < 0)
                 log_warning_errno(r, "Failed to write device timeout drop-in: %m");
 
index e1f0ff1dcbef05862ddde0d711ca480ea936ce52..235969980139fe68f2fc08a66acd8ab08b8c7a07 100644 (file)
@@ -2281,7 +2281,7 @@ int home_create_luks(
 
                 setup->temporary_image_path = TAKE_PTR(t);
 
-                r = chattr_full(t, setup->image_fd, FS_NOCOW_FL|FS_NOCOMP_FL, FS_NOCOW_FL|FS_NOCOMP_FL, NULL, NULL, CHATTR_FALLBACK_BITWISE);
+                r = chattr_full(setup->image_fd, NULL, FS_NOCOW_FL|FS_NOCOMP_FL, FS_NOCOW_FL|FS_NOCOMP_FL, NULL, NULL, CHATTR_FALLBACK_BITWISE);
                 if (r < 0 && r != -ENOANO) /* ENOANO → some bits didn't work; which we skip logging about because chattr_full() already debug logs about those flags */
                         log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r,
                                        "Failed to set file attributes on %s, ignoring: %m", setup->temporary_image_path);
index db5b1b8d4addde5b931cb50e5bbdb1fb5813aa68..aa93a86ca5c24b0a2bf46806be3038f28e70dcd6 100644 (file)
@@ -91,6 +91,7 @@ static int parse_env(
 static int acquire_user_record(
                 pam_handle_t *handle,
                 const char *username,
+                bool debug,
                 UserRecord **ret_record,
                 PamBusData **bus_data) {
 
@@ -148,12 +149,14 @@ static int acquire_user_record(
                 r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
                 if (r < 0) {
                         if (bus_error_is_unknown_service(&error)) {
-                                pam_syslog(handle, LOG_DEBUG, "systemd-homed is not available: %s", bus_error_message(&error, r));
+                                if (debug)
+                                        pam_syslog(handle, LOG_DEBUG, "systemd-homed is not available: %s", bus_error_message(&error, r));
                                 goto user_unknown;
                         }
 
                         if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_HOME)) {
-                                pam_syslog(handle, LOG_DEBUG, "Not a user managed by systemd-homed: %s", bus_error_message(&error, r));
+                                if (debug)
+                                        pam_syslog(handle, LOG_DEBUG, "Not a user managed by systemd-homed: %s", bus_error_message(&error, r));
                                 goto user_unknown;
                         }
 
@@ -265,7 +268,8 @@ static int handle_generic_user_record_error(
                 const char *user_name,
                 UserRecord *secret,
                 int ret,
-                const sd_bus_error *error) {
+                const sd_bus_error *error,
+                bool debug) {
 
         assert(user_name);
         assert(error);
@@ -301,9 +305,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR,
-                                                    "Password request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "Password request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_password(secret, STRV_MAKE(newp), true);
                 if (r < 0)
@@ -325,9 +331,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR,
-                                                    "Recovery key request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "Recovery key request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_password(secret, STRV_MAKE(newp), true);
                 if (r < 0)
@@ -348,9 +356,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR,
-                                                    "Password request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "Password request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
 
                 r = user_record_set_password(secret, STRV_MAKE(newp), true);
@@ -366,8 +376,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR, "PIN request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "PIN request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_token_pin(secret, STRV_MAKE(newp), false);
                 if (r < 0)
@@ -421,8 +434,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR, "PIN request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "PIN request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_token_pin(secret, STRV_MAKE(newp), false);
                 if (r < 0)
@@ -438,8 +454,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR, "PIN request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "PIN request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_token_pin(secret, STRV_MAKE(newp), false);
                 if (r < 0)
@@ -455,8 +474,11 @@ static int handle_generic_user_record_error(
                 if (r != PAM_SUCCESS)
                         return PAM_CONV_ERR; /* no logging here */
 
-                if (isempty(newp))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR, "PIN request aborted.");
+                if (isempty(newp)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "PIN request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = user_record_set_token_pin(secret, STRV_MAKE(newp), false);
                 if (r < 0)
@@ -519,7 +541,7 @@ static int acquire_home(
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, username, &ur, bus_data);
+        r = acquire_user_record(handle, username, debug, &ur, bus_data);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -586,7 +608,7 @@ static int acquire_home(
                         else if (sd_bus_error_has_name(&error, BUS_ERROR_HOME_LOCKED))
                                 home_locked = true; /* Similar */
                         else {
-                                r = handle_generic_user_record_error(handle, ur->user_name, secret, r, &error);
+                                r = handle_generic_user_record_error(handle, ur->user_name, secret, r, &error, debug);
                                 if (r == PAM_CONV_ERR) {
                                         /* Password/PIN prompts will fail in certain environments, for example when
                                          * we are called from OpenSSH's account or session hooks, or in systemd's
@@ -598,7 +620,8 @@ static int acquire_home(
                                         if (home_locked)
                                                 (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Home of user %s is currently locked, please unlock locally first.", ur->user_name);
 
-                                        pam_syslog(handle, please_authenticate ? LOG_ERR : LOG_DEBUG, "Failed to prompt for password/prompt.");
+                                        if (please_authenticate || debug)
+                                                pam_syslog(handle, please_authenticate ? LOG_ERR : LOG_DEBUG, "Failed to prompt for password/prompt.");
 
                                         return home_not_active || home_locked ? PAM_PERM_DENIED : PAM_CONV_ERR;
                                 }
@@ -837,7 +860,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, NULL, &ur, NULL);
+        r = acquire_user_record(handle, NULL, debug, &ur, NULL);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -949,7 +972,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
         if (r != PAM_SUCCESS)
                 return r;
 
-        r = acquire_user_record(handle, NULL, &ur, NULL);
+        r = acquire_user_record(handle, NULL, debug, &ur, NULL);
         if (r != PAM_SUCCESS)
                 return r;
 
@@ -970,8 +993,11 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
                 if (r != PAM_SUCCESS)
                         return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get new password: @PAMERR@");
 
-                if (isempty(new_password))
-                        return pam_syslog_pam_error(handle, LOG_DEBUG, PAM_AUTHTOK_ERR, "Password request aborted.");
+                if (isempty(new_password)) {
+                        if (debug)
+                                pam_syslog(handle, LOG_DEBUG, "Password request aborted.");
+                        return PAM_AUTHTOK_ERR;
+                }
 
                 r = pam_get_authtok_verify(handle, &new_password, "new password: "); /* Lower case, since PAM prefixes 'Repeat' */
                 if (r != PAM_SUCCESS)
@@ -1026,7 +1052,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok(
 
                 r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
                 if (r < 0) {
-                        r = handle_generic_user_record_error(handle, ur->user_name, old_secret, r, &error);
+                        r = handle_generic_user_record_error(handle, ur->user_name, old_secret, r, &error, debug);
                         if (r == PAM_CONV_ERR)
                                 return pam_syslog_pam_error(handle, LOG_ERR, r,
                                                             "Failed to prompt for password/prompt.");
index 4aa8204983a448b1817da8e789dbd3da09e136e4..2f54cd811486b4fffcb8642b51b917b0f69c7d89 100644 (file)
@@ -293,7 +293,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
                         return r;
 
                 /* Let's try to make a snapshot, if we can, so that the export is atomic */
-                r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
+                r = btrfs_subvol_snapshot_at(sfd, NULL, AT_FDCWD, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
                 if (r < 0) {
                         log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path);
                         e->temp_path = mfree(e->temp_path);
index d81dd13ffde4df06b37097c735e842d16b349bb9..fd79c8f01a06fef0f1d8a4d9a61f6dfc5bb3ca1c 100644 (file)
@@ -194,9 +194,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
                 BLOCK_SIGNALS(SIGINT, SIGTERM);
 
                 if (arg_btrfs_subvol)
-                        r = btrfs_subvol_snapshot_fd_full(
-                                        fd,
-                                        dest,
+                        r = btrfs_subvol_snapshot_at_full(
+                                        fd, NULL,
+                                        AT_FDCWD, dest,
                                         BTRFS_SNAPSHOT_FALLBACK_COPY|
                                         BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
                                         BTRFS_SNAPSHOT_RECURSIVE|
@@ -206,9 +206,9 @@ static int import_fs(int argc, char *argv[], void *userdata) {
                                         progress_bytes,
                                         &progress);
                 else
-                        r = copy_directory_fd_full(
-                                        fd,
-                                        dest,
+                        r = copy_directory_at_full(
+                                        fd, NULL,
+                                        AT_FDCWD, dest,
                                         COPY_REFLINK|
                                         COPY_SAME_MOUNT|
                                         COPY_HARDLINKS|
index f22eb0e3a33da5ebe2d8aa4cf0b50359dda09d64..e474dffa72ec6bbb453c5fe7bc76c6d33d41a772 100644 (file)
@@ -237,9 +237,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
                 return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
 
         if (i->flags & PULL_BTRFS_SUBVOL)
-                r = btrfs_subvol_snapshot(
-                                i->final_path,
-                                t,
+                r = btrfs_subvol_snapshot_at(
+                                AT_FDCWD, i->final_path,
+                                AT_FDCWD, t,
                                 (i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
                                 BTRFS_SNAPSHOT_FALLBACK_COPY|
                                 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
index 66f93e7d2eb2f86d0f5880c936a5e8116d99131f..c29d4fcd5da847a5da276b23b06e3a72c24b2f6e 100644 (file)
@@ -34,9 +34,22 @@ int parse_integrity_options(
                 else if (streq(word, "allow-discards")) {
                         if (ret_activate_flags)
                                 *ret_activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
-                } else if (streq(word, "no-journal")) {
-                        if (ret_activate_flags)
-                                *ret_activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
+                } else if ((val = startswith(word, "mode="))) {
+                        if (streq(val, "journal")) {
+                                if (ret_activate_flags)
+                                        *ret_activate_flags &= ~(CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_NO_JOURNAL_BITMAP);
+                        } else if (streq(val, "bitmap")) {
+                                if (ret_activate_flags) {
+                                        *ret_activate_flags &= ~CRYPT_ACTIVATE_NO_JOURNAL;
+                                        *ret_activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
+                                }
+                        } else if (streq(val, "direct")) {
+                                if (ret_activate_flags) {
+                                        *ret_activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
+                                        *ret_activate_flags &= ~CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
+                                }
+                        } else
+                                log_warning("Encountered unknown mode option '%s', ignoring.", val);
                 } else if ((val = startswith(word, "journal-watermark="))) {
                         r = parse_percent(val);
                         if (r < 0)
index 15f508902d3aee167682f2e87c1a7d76fa11f000..5df6d81a8441a312589fce77dbe812e013b8130b 100644 (file)
@@ -100,7 +100,7 @@ static int create_disk(
                 "[Service]\n"
                 "Type=oneshot\n"
                 "RemainAfterExit=yes\n"
-                "TimeoutSec=0\n"
+                "TimeoutSec=infinity\n"
                 "ExecStart=" ROOTLIBEXECDIR "/systemd-integritysetup attach '%s' '%s' '%s' '%s'\n"
                 "ExecStop=" ROOTLIBEXECDIR "/systemd-integritysetup detach '%s'\n",
                 name_escaped, device, empty_to_dash(key_file_escaped), empty_to_dash(options),
index c5ecc2b844b6d174926707be0c71789d8710c482..db94644ceba4b068aa53179ccc6f397a7b115ae3 100644 (file)
@@ -436,7 +436,7 @@ static int setup_microhttpd_server(RemoteServer *s,
                                      MHD_OPTION_ARRAY, opts,
                                      MHD_OPTION_END);
         if (!d->daemon) {
-                log_error("Failed to start µhttp daemon");
+                log_error("Failed to start μhttp daemon");
                 r = -EINVAL;
                 goto error;
         }
@@ -446,14 +446,14 @@ static int setup_microhttpd_server(RemoteServer *s,
 
         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
         if (!info) {
-                log_error("µhttp returned NULL daemon info");
+                log_error("μhttp returned NULL daemon info");
                 r = -EOPNOTSUPP;
                 goto error;
         }
 
         epoll_fd = info->listen_fd;
         if (epoll_fd < 0) {
-                log_error("µhttp epoll fd is invalid");
+                log_error("μhttp epoll fd is invalid");
                 r = -EUCLEAN;
                 goto error;
         }
index 6e993863bfbfdc5fc1aa49cf93d20be71b3783f3..8b64bc78e9ffb4a30b2d0428aeb1afab92010488 100644 (file)
@@ -149,7 +149,7 @@ int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer
  **********************************************************************
  **********************************************************************/
 
-/* This should go away as soon as µhttpd allows state to be passed around. */
+/* This should go away as soon as μhttpd allows state to be passed around. */
 RemoteServer *journal_remote_server_global;
 
 static int dispatch_raw_source_event(sd_event_source *event,
index df183354694117d1bf4a533539424469bed5093c..140e7f62235d9ee9b434ddd401d1eed1827ad13b 100644 (file)
  * enum elements with the same name. Hence let's check for the *old* name,
  * and define the new name by the value of the old name. */
 
-/* Renamed in µhttpd 0.9.51 */
+/* Renamed in μhttpd 0.9.51 */
 #ifndef MHD_USE_PIPE_FOR_SHUTDOWN
 #  define MHD_USE_ITC MHD_USE_PIPE_FOR_SHUTDOWN
 #endif
 
-/* Renamed in µhttpd 0.9.52 */
+/* Renamed in μhttpd 0.9.52 */
 #ifndef MHD_USE_EPOLL_LINUX_ONLY
 #  define MHD_USE_EPOLL MHD_USE_EPOLL_LINUX_ONLY
 #endif
 
-/* Renamed in µhttpd 0.9.52 */
+/* Renamed in μhttpd 0.9.52 */
 #ifndef MHD_USE_SSL
 #  define MHD_USE_TLS MHD_USE_SSL
 #endif
 
-/* Renamed in µhttpd 0.9.53 */
+/* Renamed in μhttpd 0.9.53 */
 #ifndef MHD_USE_POLL_INTERNALLY
 #  define MHD_USE_POLL_INTERNAL_THREAD MHD_USE_POLL_INTERNALLY
 #endif
@@ -38,7 +38,7 @@
 #  define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE
 #endif
 
-/* Renamed in µhttpd 0.9.74 (8c644fc1f4d498ea489add8d40a68f5d3e5899fa) */
+/* Renamed in μhttpd 0.9.74 (8c644fc1f4d498ea489add8d40a68f5d3e5899fa) */
 #ifndef MHD_HTTP_CONTENT_TOO_LARGE
 #  ifdef MHD_HTTP_PAYLOAD_TOO_LARGE
 #    define MHD_HTTP_CONTENT_TOO_LARGE MHD_HTTP_PAYLOAD_TOO_LARGE /* 0.9.53 or newer */
index 1763a2556ea9ef3788ee57fcd38bc48dcf8edc44..2932a190ff7e4bfc66a9f4a46753abaca4983c26 100644 (file)
@@ -238,13 +238,6 @@ void server_space_usage_message(Server *s, JournalStorage *storage) {
                               NULL);
 }
 
-static bool uid_for_system_journal(uid_t uid) {
-
-        /* Returns true if the specified UID shall get its data stored in the system journal. */
-
-        return uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY;
-}
-
 static void server_add_acls(ManagedJournalFile *f, uid_t uid) {
         assert(f);
 
index 735e2c5e8bac63e4444cfae56315b2998347ece7..222b036698c86d4e2cfb16060dd718f6bc7a8aa0 100644 (file)
@@ -938,7 +938,7 @@ int server_open_stdout_socket(Server *s, const char *stdout_socket) {
 
                 (void) chmod(sa.un.sun_path, 0666);
 
-                if (listen(s->stdout_fd, SOMAXCONN) < 0)
+                if (listen(s->stdout_fd, SOMAXCONN_DELUXE) < 0)
                         return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
         } else
                 (void) fd_nonblock(s->stdout_fd, true);
diff --git a/src/kernel-install/kernel-install.c b/src/kernel-install/kernel-install.c
new file mode 100644 (file)
index 0000000..c0988b7
--- /dev/null
@@ -0,0 +1,1246 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <getopt.h>
+#include <stdbool.h>
+
+#include "build.h"
+#include "boot-entry.h"
+#include "chase.h"
+#include "conf-files.h"
+#include "env-file.h"
+#include "env-util.h"
+#include "exec-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "find-esp.h"
+#include "id128-util.h"
+#include "kernel-image.h"
+#include "main-func.h"
+#include "mkdir.h"
+#include "parse-argument.h"
+#include "path-util.h"
+#include "pretty-print.h"
+#include "rm-rf.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "tmpfile-util.h"
+#include "verbs.h"
+
+static bool arg_verbose = false;
+static char *arg_esp_path = NULL;
+static char *arg_xbootldr_path = NULL;
+static int arg_make_entry_directory = -1; /* tristate */
+
+STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
+
+typedef enum Action {
+        ACTION_ADD,
+        ACTION_REMOVE,
+        ACTION_INSPECT,
+        _ACTION_MAX,
+        _ACTION_INVALID = -EINVAL,
+} Action;
+
+typedef enum Layout {
+        LAYOUT_AUTO,
+        LAYOUT_UKI,
+        LAYOUT_BLS,
+        LAYOUT_OTHER,
+        _LAYOUT_MAX,
+        _LAYOUT_INVALID = -EINVAL,
+} Layout;
+
+static const char * const layout_table[_LAYOUT_MAX] = {
+        [LAYOUT_AUTO]  = "auto",
+        [LAYOUT_UKI]   = "uki",
+        [LAYOUT_BLS]   = "bls",
+        [LAYOUT_OTHER] = "other",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(layout, Layout);
+
+typedef struct Context {
+        int rfd;
+        Action action;
+        sd_id128_t machine_id;
+        bool machine_id_is_random;
+        KernelImageType kernel_image_type;
+        Layout layout;
+        char *layout_other;
+        char *conf_root;
+        char *boot_root;
+        BootEntryTokenType entry_token_type;
+        char *entry_token;
+        char *entry_dir;
+        char *version;
+        char *kernel;
+        char **initrds;
+        char *initrd_generator;
+        char *uki_generator;
+        char *staging_area;
+        char **plugins;
+        char **argv;
+        char **envp;
+} Context;
+
+static void context_done(Context *c) {
+        assert(c);
+
+        free(c->layout_other);
+        free(c->conf_root);
+        free(c->boot_root);
+        free(c->entry_token);
+        free(c->entry_dir);
+        free(c->version);
+        free(c->kernel);
+        strv_free(c->initrds);
+        free(c->initrd_generator);
+        free(c->uki_generator);
+        if (c->action == ACTION_INSPECT)
+                free(c->staging_area);
+        else
+                rm_rf_physical_and_free(c->staging_area);
+        strv_free(c->plugins);
+        strv_free(c->argv);
+        strv_free(c->envp);
+
+        safe_close(c->rfd);
+}
+
+static int context_open_root(Context *c) {
+        assert(c);
+        assert(c->rfd < 0);
+
+        c->rfd = open("/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+        if (c->rfd < 0)
+                return log_error_errno(errno, "Failed to open root directory: %m");
+
+        return 0;
+}
+
+static const char* context_get_layout(const Context *c) {
+        assert(c);
+        assert(c->layout >= 0);
+
+        return c->layout_other ?: layout_to_string(c->layout);
+}
+
+static int context_set_layout(Context *c, const char *s, const char *source) {
+        Layout t;
+
+        assert(c);
+        assert(source);
+
+        if (c->layout >= 0 || !s)
+                return 0;
+
+        assert(!c->layout_other);
+
+        t = layout_from_string(s);
+        if (t >= 0)
+                c->layout = t;
+        else if (isempty(s))
+                c->layout = LAYOUT_AUTO;
+        else {
+                c->layout_other = strdup(s);
+                if (!c->layout_other)
+                        return log_oom();
+
+                c->layout = LAYOUT_OTHER;
+        }
+
+        log_debug("layout=%s set via %s", context_get_layout(c), source);
+        return 1;
+}
+
+static int context_set_machine_id(Context *c, const char *s, const char *source) {
+        int r;
+
+        assert(c);
+        assert(source);
+
+        if (!sd_id128_is_null(c->machine_id) || !s)
+                return 0;
+
+        r = sd_id128_from_string(s, &c->machine_id);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse machine ID specified via %s, ignoring.", source);
+
+        if (sd_id128_is_null(c->machine_id))
+                return 0;
+
+        log_debug("MACHINE_ID=%s set via %s.", SD_ID128_TO_STRING(c->machine_id), source);
+        return 1;
+}
+
+static int context_set_string(const char *s, const char *source, const char *name, char **dest) {
+        char *p;
+
+        assert(source);
+        assert(name);
+        assert(dest);
+
+        if (*dest || !s)
+                return 0;
+
+        p = strdup(s);
+        if (!p)
+                return log_oom();
+
+        log_debug("%s (%s) set via %s.", name, p, source);
+
+        *dest = p;
+        return 1;
+}
+
+static int context_set_initrd_generator(Context *c, const char *s, const char *source) {
+        assert(c);
+        return context_set_string(s, source, "INITRD_GENERATOR", &c->initrd_generator);
+}
+
+static int context_set_uki_generator(Context *c, const char *s, const char *source) {
+        assert(c);
+        return context_set_string(s, source, "UKI_GENERATOR", &c->uki_generator);
+}
+
+static int context_set_version(Context *c, const char *s) {
+        assert(c);
+
+        if (!filename_is_valid(s))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid version specified: %s", s);
+
+        return context_set_string(s, "command line", "kernel version", &c->version);
+}
+
+static int context_set_path(Context *c, int rfd, const char *s, const char *source, const char *name, char **dest) {
+        char *p;
+        int r;
+
+        assert(c);
+        assert(source);
+        assert(name);
+        assert(dest);
+
+        if (*dest || !s)
+                return 0;
+
+        if (rfd >= 0)
+                r = chaseat(rfd, s, CHASE_AT_RESOLVE_IN_ROOT, &p, /* ret_fd = */ NULL);
+        else
+                r = chase(s, /* root = */ NULL, 0, &p, /* ret_fd = */ NULL);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to chase path %s for %s specified via %s, ignoring: %m",
+                                         s, name, source);
+
+        log_debug("%s (%s) set via %s.", name, p, source);
+
+        *dest = p;
+        return 1;
+}
+
+static int context_set_boot_root(Context *c, const char *s, const char *source) {
+        assert(c);
+        return context_set_path(c, c->rfd, s, source, "BOOT_ROOT", &c->boot_root);
+}
+
+static int context_set_conf_root(Context *c, const char *s, const char *source) {
+        assert(c);
+        return context_set_path(c, c->rfd, s, source, "CONF_ROOT", &c->conf_root);
+}
+
+static int context_set_kernel(Context *c, const char *s) {
+        assert(c);
+        /* The path specified via command line should be relative to CWD. */
+        return context_set_path(c, AT_FDCWD, s, "command line", "kernel image file", &c->kernel);
+}
+
+static int context_set_path_strv(Context *c, int rfd, char* const* strv, const char *source, const char *name, char ***dest) {
+        _cleanup_strv_free_ char **w = NULL;
+        int r;
+
+        assert(c);
+        assert(source);
+        assert(name);
+        assert(dest);
+
+        if (*dest)
+                return 0;
+
+        STRV_FOREACH(s, strv) {
+                char *p;
+
+                if (rfd >= 0)
+                        r = chaseat(rfd, *s, CHASE_AT_RESOLVE_IN_ROOT, &p, /* ret_fd = */ NULL);
+                else
+                        r = chase(*s, /* root = */ NULL, 0, &p, /* ret_fd = */ NULL);
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to chase path %s for %s specified via %s: %m",
+                                                 *s, name, source);
+
+                r = strv_consume(&w, p);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        if (strv_isempty(w))
+                return 0;
+
+        log_debug("%s set via %s", name, source);
+
+        *dest = TAKE_PTR(w);
+        return 1;
+}
+
+static int context_set_plugins(Context *c, const char *s, const char *source) {
+        _cleanup_strv_free_ char **v = NULL;
+
+        assert(c);
+
+        if (c->plugins || !s)
+                return 0;
+
+        v = strv_split(s, NULL);
+        if (!v)
+                return log_oom();
+
+        return context_set_path_strv(c, c->rfd, v, source, "plugins", &c->plugins);
+}
+
+static int context_set_initrds(Context *c, char* const* strv) {
+        assert(c);
+        return context_set_path_strv(c, AT_FDCWD, strv, "command line", "initrds", &c->initrds);
+}
+
+static int context_load_environment(Context *c) {
+        assert(c);
+
+        (void) context_set_machine_id(c, getenv("MACHINE_ID"), "environment");
+        (void) context_set_boot_root(c, getenv("BOOT_ROOT"), "environment");
+        (void) context_set_conf_root(c, getenv("KERNEL_INSTALL_CONF_ROOT"), "environment");
+        (void) context_set_plugins(c, getenv("KERNEL_INSTALL_PLUGINS"), "environment");
+        return 0;
+}
+
+static int context_ensure_conf_root(Context *c) {
+        int r;
+
+        assert(c);
+
+        if (c->conf_root)
+                return 0;
+
+        r = chaseat(c->rfd, "/etc/kernel", CHASE_AT_RESOLVE_IN_ROOT, &c->conf_root, /* ret_fd = */ NULL);
+        if (r < 0)
+                log_debug_errno(r, "Failed to chase /etc/kernel, ignoring: %m");
+
+        return 0;
+}
+
+static int context_load_install_conf_one(Context *c, const char *path) {
+        _cleanup_close_ int fd = -EBADF;
+        _cleanup_free_ char
+                *conf = NULL, *machine_id = NULL, *boot_root = NULL, *layout = NULL,
+                *initrd_generator = NULL, *uki_generator = NULL;
+        int r;
+
+        assert(c);
+        assert(path);
+
+        conf = path_join(path, "install.conf");
+        if (!conf)
+                return log_oom();
+
+        r = chaseat(c->rfd, conf, CHASE_AT_RESOLVE_IN_ROOT, NULL, &fd);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to chase %s: %m", conf);
+
+        log_debug("Loading %s…", conf);
+
+        r = parse_env_file_fd(fd, conf,
+                              "MACHINE_ID",       &machine_id,
+                              "BOOT_ROOT",        &boot_root,
+                              "layout",           &layout,
+                              "initrd_generator", &initrd_generator,
+                              "uki_generator",    &uki_generator);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse '%s': %m", conf);
+
+        (void) context_set_machine_id(c, machine_id, conf);
+        (void) context_set_boot_root(c, boot_root, conf);
+        (void) context_set_layout(c, layout, conf);
+        (void) context_set_initrd_generator(c, initrd_generator, conf);
+        (void) context_set_uki_generator(c, uki_generator, conf);
+
+        log_debug("Loaded %s.", conf);
+        return 1;
+}
+
+static int context_load_install_conf(Context *c) {
+        int r;
+
+        assert(c);
+
+        if (c->conf_root) {
+                r = context_load_install_conf_one(c, c->conf_root);
+                if (r != 0)
+                        return r;
+        }
+
+        STRV_FOREACH(p, STRV_MAKE("/etc/kernel", "/usr/lib/kernel")) {
+                r = context_load_install_conf_one(c, *p);
+                if (r != 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static int context_load_machine_info(Context *c) {
+        _cleanup_close_ int fd = -EBADF;
+        _cleanup_free_ char *machine_id = NULL, *layout = NULL;
+        static const char *path = "/etc/machine-info";
+        int r;
+
+        assert(c);
+
+        /* If the user configured an explicit machine ID in /etc/machine-info to use for our purpose, we'll
+         * use that instead (for compatibility). */
+
+        if (!sd_id128_is_null(c->machine_id) && c->layout >= 0)
+                return 0;
+
+        r = chaseat(c->rfd, path, CHASE_AT_RESOLVE_IN_ROOT, NULL, &fd);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to chase %s: %m", path);
+
+        log_debug("Loading %s…", path);
+
+        r = parse_env_file_fd(fd, path,
+                              "KERNEL_INSTALL_MACHINE_ID", &machine_id,
+                              "KERNEL_INSTALL_LAYOUT", &layout);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse '%s': %m", path);
+
+        (void) context_set_machine_id(c, machine_id, path);
+        (void) context_set_layout(c, layout, path);
+        return 0;
+}
+
+static int context_load_machine_id(Context *c) {
+        int r;
+
+        assert(c);
+
+        r = id128_get_machine_at(c->rfd, &c->machine_id);
+        if (r < 0) {
+                if (ERRNO_IS_MACHINE_ID_UNSET(r))
+                        return 0;
+                return log_error_errno(r, "Failed to load machine ID from /etc/machine-id: %m");
+        }
+
+        log_debug("MACHINE_ID=%s set via /etc/machine-id.", SD_ID128_TO_STRING(c->machine_id));
+        return 1; /* loaded */
+}
+
+static int context_ensure_machine_id(Context *c) {
+        int r;
+
+        assert(c);
+
+        if (!sd_id128_is_null(c->machine_id))
+                return 0;
+
+        /* If /etc/machine-id is initialized we'll use it. */
+        r = context_load_machine_id(c);
+        if (r != 0)
+                return r;
+
+        /* Otherwise we'll use a freshly generated one. */
+        r = sd_id128_randomize(&c->machine_id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate random ID: %m");
+
+        c->machine_id_is_random = true;
+        log_debug("New machine ID '%s' generated.", SD_ID128_TO_STRING(c->machine_id));
+        return 0;
+}
+
+static int context_acquire_xbootldr(Context *c) {
+        int r;
+
+        assert(c);
+        assert(!c->boot_root);
+
+        r = find_xbootldr_and_warn_at(
+                        /* rfd = */ c->rfd,
+                        /* path = */ arg_xbootldr_path,
+                        /* unprivileged_mode= */ -1,
+                        /* ret_path = */ &c->boot_root,
+                        /* ret_uuid = */ NULL,
+                        /* ret_devid = */ NULL);
+        if (r == -ENOKEY) {
+                log_debug_errno(r, "Couldn't find an XBOOTLDR partition.");
+                return 0;
+        }
+        if (r == -EACCES && geteuid() != 0)
+                return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
+        if (r < 0)
+                return r;
+
+        log_debug("Using XBOOTLDR partition at %s as $BOOT_ROOT.", c->boot_root);
+        return 1; /* found */
+}
+
+static int context_acquire_esp(Context *c) {
+        int r;
+
+        assert(c);
+        assert(!c->boot_root);
+
+        r = find_esp_and_warn_at(
+                        /* rfd = */ c->rfd,
+                        /* path = */ arg_esp_path,
+                        /* unprivileged_mode= */ -1,
+                        /* ret_path = */ &c->boot_root,
+                        /* ret_part = */ NULL,
+                        /* ret_pstart = */ NULL,
+                        /* ret_psize = */ NULL,
+                        /* ret_uuid = */ NULL,
+                        /* ret_devid = */ NULL);
+        if (r == -ENOKEY) {
+                log_debug_errno(r, "Couldn't find EFI system partition, ignoring.");
+                return 0;
+        }
+        if (r == -EACCES && geteuid() != 0)
+                return log_error_errno(r, "Failed to determine EFI system partition: %m");
+        if (r < 0)
+                return r;
+
+        log_debug("Using EFI System Partition at %s as $BOOT_ROOT.", c->boot_root);
+        return 1; /* found */
+}
+
+static int context_ensure_boot_root(Context *c) {
+        int r;
+
+        assert(c);
+
+        /* If BOOT_ROOT is specified via environment or install.conf, then use it. */
+        if (c->boot_root)
+                return 0;
+
+        /* Otherwise, use XBOOTLDR partition, if mounted. */
+        r = context_acquire_xbootldr(c);
+        if (r != 0)
+                return r;
+
+        /* Otherwise, use EFI system partition, if mounted. */
+        r = context_acquire_esp(c);
+        if (r != 0)
+                return r;
+
+        /* If all else fails, use /boot. */
+        r = chaseat(c->rfd, "/boot", CHASE_AT_RESOLVE_IN_ROOT, &c->boot_root, /* ret_fd = */ NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to chase '/boot': %m");
+
+        log_debug("KERNEL_INSTALL_BOOT_ROOT autodetection yielded no candidates, using \"%s\".", c->boot_root);
+        return 0;
+}
+
+static int context_ensure_entry_token(Context *c) {
+        int r;
+
+        assert(c);
+
+        /* Now that we determined the machine ID to use, let's determine the "token" for the boot loader
+         * entry to generate. We use that for naming the directory below $BOOT where we want to place the
+         * kernel/initrd and related resources, as well for naming the .conf boot loader spec entry.
+         * Typically this is just the machine ID, but it can be anything else, too, if we are told so. */
+
+        r = boot_entry_token_ensure_at(
+                        c->rfd,
+                        c->conf_root,
+                        c->machine_id,
+                        c->machine_id_is_random,
+                        &c->entry_token_type,
+                        &c->entry_token);
+        if (r < 0)
+                return r;
+
+        log_debug("Using entry token: %s", c->entry_token);
+        return 0;
+}
+
+static int context_load_plugins(Context *c) {
+        int r;
+
+        assert(c);
+
+        if (c->plugins)
+                return 0;
+
+        r = conf_files_list_strv_at(
+                        &c->plugins,
+                        ".install",
+                        c->rfd,
+                        CONF_FILES_EXECUTABLE | CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED,
+                        STRV_MAKE_CONST("/etc/kernel/install.d", "/usr/lib/kernel/install.d"));
+        if (r < 0)
+                return log_error_errno(r, "Failed to find plugins: %m");
+
+        return 0;
+}
+
+static int context_init(Context *c) {
+        int r;
+
+        assert(c);
+
+        r = context_open_root(c);
+        if (r < 0)
+                return r;
+
+        r = context_load_environment(c);
+        if (r < 0)
+                return r;
+
+        r = context_ensure_conf_root(c);
+        if (r < 0)
+                return r;
+
+        r = context_load_install_conf(c);
+        if (r < 0)
+                return r;
+
+        r = context_load_machine_info(c);
+        if (r < 0)
+                return r;
+
+        r = context_ensure_machine_id(c);
+        if (r < 0)
+                return r;
+
+        r = context_ensure_boot_root(c);
+        if (r < 0)
+                return r;
+
+        r = context_ensure_entry_token(c);
+        if (r < 0)
+                return r;
+
+        r = context_load_plugins(c);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int context_inspect_kernel(Context *c) {
+        assert(c);
+
+        if (!c->kernel)
+                return 0;
+
+        return inspect_kernel(c->rfd, c->kernel, &c->kernel_image_type, NULL, NULL, NULL);
+}
+
+static int context_ensure_layout(Context *c) {
+        int r;
+
+        assert(c);
+        assert(c->boot_root);
+        assert(c->entry_token);
+
+        if (c->layout >= 0 && c->layout != LAYOUT_AUTO)
+                return 0;
+
+        /* No layout configured by the administrator. Let's try to figure it out automatically from metadata
+         * already contained in $BOOT_ROOT. */
+
+        if (c->kernel_image_type == KERNEL_IMAGE_TYPE_UKI) {
+                c->layout = LAYOUT_UKI;
+                log_debug("Kernel image type is %s, using layout=%s.",
+                          kernel_image_type_to_string(c->kernel_image_type), layout_to_string(c->layout));
+                return 0;
+        }
+
+        _cleanup_free_ char *srel_path = path_join(c->boot_root, "loader/entries.srel");
+        if (!srel_path)
+                return log_oom();
+
+        _cleanup_free_ char *srel = NULL;
+        r = read_one_line_file_at(c->rfd, srel_path, &srel);
+        if (r >= 0) {
+                if (streq(srel, "type1"))
+                        /* The loader/entries.srel file clearly indicates that the installed boot loader
+                         * implements the proper standard upstream boot loader spec for Type #1 entries.
+                         * Let's default to that, then. */
+                        c->layout = LAYOUT_BLS;
+                else
+                        /* The loader/entries.srel file indicates some other spec is implemented and owns the
+                         * /loader/entries/ directory. Since we have no idea what that means, let's stay away
+                         * from it by default. */
+                        c->layout = LAYOUT_OTHER;
+
+                log_debug("%s with '%s' found, using layout=%s.", srel_path, srel, layout_to_string(c->layout));
+                return 0;
+        } else if (r != -ENOENT)
+                return log_error_errno(r, "Failed to read %s: %m", srel_path);
+
+        _cleanup_free_ char *entry_token_path = path_join(c->boot_root, c->entry_token);
+        if (!entry_token_path)
+                return log_oom();
+
+        r = is_dir_full(c->rfd, entry_token_path, /* follow = */ false);
+        if (r < 0 && r != -ENOENT)
+                return log_error_errno(r, "Failed to check if '%s' is a directory: %m", entry_token_path);
+        if (r > 0) {
+                /* If the metadata in $BOOT_ROOT doesn't tell us anything, then check if the entry token
+                 * directory already exists. If so, let's assume it's the standard boot loader spec, too. */
+                c->layout = LAYOUT_BLS;
+                log_debug("%s exists, using layout=%s.", entry_token_path, layout_to_string(c->layout));
+                return 0;
+        }
+
+        /* There's no metadata in $BOOT_ROOT, and apparently no entry token directory installed? Then we
+         * really don't know anything. */
+        c->layout = LAYOUT_OTHER;
+        log_debug("Entry-token directory not found, using layout=%s.", layout_to_string(c->layout));
+        return 0;
+}
+
+static int context_set_up_staging_area(Context *c) {
+        static const char *template = "/tmp/kernel-install.staging.XXXXXX";
+        int r;
+
+        assert(c);
+
+        if (c->staging_area)
+                return 0;
+
+        if (c->action == ACTION_INSPECT) {
+                /* This is only used for display. The directory will not be created. */
+                c->staging_area = strdup(template);
+                if (!c->staging_area)
+                        return log_oom();
+        } else {
+                r = mkdtemp_malloc(template, &c->staging_area);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create staging area: %m");
+        }
+
+        return 0;
+}
+
+static int context_build_entry_dir(Context *c) {
+        assert(c);
+        assert(c->boot_root);
+        assert(c->entry_token);
+        assert(c->version || c->action == ACTION_INSPECT);
+
+        if (c->entry_dir)
+                return 0;
+
+        c->entry_dir = path_join(c->boot_root, c->entry_token, c->version ?: "KERNEL_VERSION");
+        if (!c->entry_dir)
+                return log_oom();
+
+        log_debug("Using ENTRY_DIR=%s", c->entry_dir);
+        return 0;
+}
+
+static bool context_should_make_entry_dir(Context *c) {
+        assert(c);
+
+        /* Compatibility with earlier versions that used the presence of $BOOT_ROOT/$ENTRY_TOKEN to signal to
+         * 00-entry-directory to create $ENTRY_DIR to serve as the indication to use or to not use the BLS */
+
+        if (arg_make_entry_directory < 0)
+                return c->layout == LAYOUT_BLS;
+
+        return arg_make_entry_directory;
+}
+
+static int context_make_entry_dir(Context *c) {
+        _cleanup_close_ int fd = -EBADF;
+
+        assert(c);
+        assert(c->entry_dir);
+
+        if (c->action != ACTION_ADD)
+                return 0;
+
+        if (!context_should_make_entry_dir(c))
+                return 0;
+
+        log_debug("mkdir -p %s", c->entry_dir);
+        fd = chase_and_openat(c->rfd, c->entry_dir, CHASE_AT_RESOLVE_IN_ROOT | CHASE_MKDIR_0755,
+                              O_CLOEXEC | O_CREAT | O_DIRECTORY | O_PATH, NULL);
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to make directory '%s': %m", c->entry_dir);
+
+        return 0;
+}
+
+static int context_remove_entry_dir(Context *c) {
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -EBADF;
+        struct stat st;
+        int r;
+
+        assert(c);
+        assert(c->entry_dir);
+
+        if (c->action != ACTION_REMOVE)
+                return 0;
+
+        if (!context_should_make_entry_dir(c))
+                return 0;
+
+        log_debug("rm -rf %s", c->entry_dir);
+        fd = chase_and_openat(c->rfd, c->entry_dir, CHASE_AT_RESOLVE_IN_ROOT, O_CLOEXEC | O_DIRECTORY, &p);
+        if (fd < 0) {
+                if (IN_SET(fd, -ENOTDIR, -ENOENT))
+                        return 0;
+                return log_debug_errno(fd, "Failed to chase and open %s, ignoring: %m", c->entry_dir);
+        }
+
+        if (fstat(fd, &st) < 0)
+                return log_debug_errno(errno, "Failed to stat %s: %m", p);
+
+        r = rm_rf_children(TAKE_FD(fd), REMOVE_PHYSICAL|REMOVE_MISSING_OK|REMOVE_CHMOD, &st);
+        if (r < 0)
+                log_debug_errno(r, "Failed to remove children of %s, ignoring: %m", p);
+
+        if (unlinkat(c->rfd, p, AT_REMOVEDIR) < 0)
+                log_debug_errno(errno, "Failed to remove %s, ignoring: %m", p);
+
+        return 0;
+}
+
+static int context_build_arguments(Context *c) {
+        _cleanup_strv_free_ char **a = NULL;
+        const char *verb;
+        int r;
+
+        assert(c);
+        assert(c->entry_dir);
+
+        if (c->argv)
+                return 0;
+
+        switch (c->action) {
+        case ACTION_ADD:
+                assert(c->version);
+                assert(c->kernel);
+                verb = "add";
+                break;
+
+        case ACTION_REMOVE:
+                assert(c->version);
+                assert(!c->kernel);
+                assert(!c->initrds);
+                verb = "remove";
+                break;
+
+        case ACTION_INSPECT:
+                assert(!c->version);
+                assert(!c->initrds);
+                verb = "add|remove";
+                break;
+
+        default:
+                assert_not_reached();
+        }
+
+        a = strv_new("dummy-arg", /* to make strv_free() works for this variable. */
+                     verb,
+                     c->version ?: "KERNEL_VERSION",
+                     c->entry_dir);
+        if (!a)
+                return log_oom();
+
+        if (c->action == ACTION_ADD) {
+                r = strv_extend(&a, c->kernel);
+                if (r < 0)
+                        return log_oom();
+
+                r = strv_extend_strv(&a, c->initrds, /* filter_duplicates = */ false);
+                if (r < 0)
+                        return log_oom();
+
+        } else if (c->action == ACTION_INSPECT) {
+                r = strv_extend(&a, c->kernel ?: "[KERNEL_IMAGE]");
+                if (r < 0)
+                        return log_oom();
+
+                r = strv_extend(&a, "[INITRD...]");
+                if (r < 0)
+                        return log_oom();
+        }
+
+        c->argv = TAKE_PTR(a);
+        return 0;
+}
+
+static int context_build_environment(Context *c) {
+        _cleanup_strv_free_ char **e = NULL;
+        int r;
+
+        assert(c);
+
+        if (c->envp)
+                return 0;
+
+        r = strv_env_assign_many(&e,
+                                 "LC_COLLATE",                      SYSTEMD_DEFAULT_LOCALE,
+                                 "KERNEL_INSTALL_VERBOSE",          one_zero(arg_verbose),
+                                 "KERNEL_INSTALL_IMAGE_TYPE",       kernel_image_type_to_string(c->kernel_image_type),
+                                 "KERNEL_INSTALL_MACHINE_ID",       SD_ID128_TO_STRING(c->machine_id),
+                                 "KERNEL_INSTALL_ENTRY_TOKEN",      c->entry_token,
+                                 "KERNEL_INSTALL_BOOT_ROOT",        c->boot_root,
+                                 "KERNEL_INSTALL_LAYOUT",           context_get_layout(c),
+                                 "KERNEL_INSTALL_INITRD_GENERATOR", strempty(c->initrd_generator),
+                                 "KERNEL_INSTALL_UKI_GENERATOR",    strempty(c->uki_generator),
+                                 "KERNEL_INSTALL_STAGING_AREA",     c->staging_area);
+        if (r < 0)
+                return log_error_errno(r, "Failed to build environment variables for plugins: %m");
+
+        c->envp = TAKE_PTR(e);
+        return 0;
+}
+
+static int context_prepare_execution(Context *c) {
+        int r;
+
+        assert(c);
+
+        r = context_inspect_kernel(c);
+        if (r < 0)
+                return r;
+
+        r = context_ensure_layout(c);
+        if (r < 0)
+                return r;
+
+        r = context_set_up_staging_area(c);
+        if (r < 0)
+                return r;
+
+        r = context_build_entry_dir(c);
+        if (r < 0)
+                return r;
+
+        r = context_build_arguments(c);
+        if (r < 0)
+                return r;
+
+        r = context_build_environment(c);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int context_execute(Context *c) {
+        int r;
+
+        assert(c);
+
+        r = context_make_entry_dir(c);
+        if (r < 0)
+                return r;
+
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *x = strv_join_full(c->plugins, "", "\n  ", /* escape_separator = */ false);
+                log_debug("Using plugins: %s", strna(x));
+
+                _cleanup_free_ char *y = strv_join_full(c->envp, "", "\n  ", /* escape_separator = */ false);
+                log_debug("Plugin environment: %s", strna(y));
+
+                _cleanup_free_ char *z = strv_join(strv_skip(c->argv, 1), " ");
+                log_debug("Plugin arguments: %s", strna(z));
+        }
+
+        r = execute_strv(
+                        /* name = */ NULL,
+                        c->plugins,
+                        /* root = */ NULL,
+                        USEC_INFINITY,
+                        /* callbacks = */ NULL,
+                        /* callback_args = */ NULL,
+                        c->argv,
+                        c->envp,
+                        EXEC_DIR_SKIP_REMAINING);
+        if (r < 0)
+                return r;
+
+        r = context_remove_entry_dir(c);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int verb_add(int argc, char *argv[], void *userdata) {
+        Context *c = ASSERT_PTR(userdata);
+        int r;
+
+        assert(argc >= 3);
+        assert(argv);
+
+        c->action = ACTION_ADD;
+
+        r = context_set_version(c, argv[1]);
+        if (r < 0)
+                return r;
+
+        r = context_set_kernel(c, argv[2]);
+        if (r < 0)
+                return r;
+
+        r = context_set_initrds(c, strv_skip(argv, 3));
+        if (r < 0)
+                return r;
+
+        r = context_prepare_execution(c);
+        if (r < 0)
+                return r;
+
+        return context_execute(c);
+}
+
+static int run_as_installkernel(int argc, char *argv[], Context *c) {
+        /* kernel's install.sh invokes us as
+         *   /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
+         * We ignore the last two arguments. */
+        if (optind + 2 > argc)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'installkernel' command requires at least two arguments.");
+
+        return verb_add(3, STRV_MAKE("add", argv[optind], argv[optind+1]), c);
+}
+
+static int verb_remove(int argc, char *argv[], void *userdata) {
+        Context *c = ASSERT_PTR(userdata);
+        int r;
+
+        assert(argc == 2);
+        assert(argv);
+
+        c->action = ACTION_REMOVE;
+
+        r = context_set_version(c, argv[1]);
+        if (r < 0)
+                return r;
+
+        r = context_prepare_execution(c);
+        if (r < 0)
+                return r;
+
+        return context_execute(c);
+}
+
+static int verb_inspect(int argc, char *argv[], void *userdata) {
+        Context *c = ASSERT_PTR(userdata);
+        _cleanup_free_ char *joined = NULL;
+        int r;
+
+        c->action = ACTION_INSPECT;
+
+        if (argc >= 2) {
+                r = context_set_kernel(c, argv[1]);
+                if (r < 0)
+                        return r;
+        }
+
+        r = context_prepare_execution(c);
+        if (r < 0)
+                return r;
+
+        printf("%sBoot Loader Entries:%s\n", ansi_underline(), ansi_normal());
+        printf("    $BOOT: %s\n", c->boot_root);
+        printf("    Token: %s\n", c->entry_token);
+        puts("");
+
+        printf("%sUsing plugins:%s\n", ansi_underline(), ansi_normal());
+        strv_print_full(c->plugins, "    ");
+        puts("");
+
+        printf("%sPlugin environment:%s\n", ansi_underline(), ansi_normal());
+        strv_print_full(c->envp, "    ");
+        puts("");
+
+        printf("%sPlugin arguments:%s\n", ansi_underline(), ansi_normal());
+        joined = strv_join(strv_skip(c->argv, 1), " ");
+        printf("    %s\n", strna(joined));
+
+        return 0;
+}
+
+static bool bypass(void) {
+        int r;
+
+        r = getenv_bool("KERNEL_INSTALL_BYPASS");
+        if (r < 0 && r != -ENXIO)
+                log_debug_errno(r, "Failed to parse $KERNEL_INSTALL_BYPASS, assuming no.");
+        if (r <= 0)
+                return false;
+
+        log_debug("$KERNEL_INSTALL_BYPASS is enabled, skipping execution.");
+        return true;
+}
+
+static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("kernel-install", "8", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
+               "%2$sAdd and remove kernel and initrd images to and from /boot%3$s\n"
+               "\nUsage:\n"
+               "  %1$s [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE...]\n"
+               "  %1$s [OPTIONS...] remove KERNEL-VERSION\n"
+               "  %1$s [OPTIONS...] inspect [KERNEL-IMAGE]\n"
+               "\nOptions:\n"
+               "  -h --help              Show this help\n"
+               "     --version           Show package version\n"
+               "  -v --verbose           Increase verbosity\n"
+               "     --esp-path=PATH     Path to the EFI System Partition (ESP)\n"
+               "     --boot-path=PATH    Path to the $BOOT partition\n"
+               "     --make-entry-directory=yes|no|auto\n"
+               "                         Create $BOOT/ENTRY-TOKEN/ directory\n"
+               "     --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
+               "                         Entry token to use for this installation\n"
+               "\nSee the %4$s for details.\n",
+               program_invocation_short_name,
+               ansi_highlight(),
+               ansi_normal(),
+               link);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[], Context *c) {
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_ESP_PATH,
+                ARG_BOOT_PATH,
+                ARG_MAKE_ENTRY_DIRECTORY,
+                ARG_ENTRY_TOKEN,
+        };
+        static const struct option options[] = {
+                { "help",                 no_argument,       NULL, 'h'                      },
+                { "version",              no_argument,       NULL, ARG_VERSION              },
+                { "verbose",              no_argument,       NULL, 'v'                      },
+                { "esp-path",             required_argument, NULL, ARG_ESP_PATH             },
+                { "boot-path",            required_argument, NULL, ARG_BOOT_PATH            },
+                { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
+                { "entry-token",          required_argument, NULL, ARG_ENTRY_TOKEN          },
+                {}
+        };
+        int t, r;
+
+        assert(argc >= 0);
+        assert(argv);
+        assert(c);
+
+        while ((t = getopt_long(argc, argv, "hv", options, NULL)) >= 0)
+                switch (t) {
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        return version();
+
+                case 'v':
+                        log_set_max_level(LOG_DEBUG);
+                        arg_verbose = true;
+                        break;
+
+                case ARG_ESP_PATH:
+                        r = parse_path_argument(optarg, /* suppress_root = */ false, &arg_esp_path);
+                        if (r < 0)
+                                return log_oom();
+                        break;
+
+                case ARG_BOOT_PATH:
+                        r = parse_path_argument(optarg, /* suppress_root = */ false, &arg_xbootldr_path);
+                        if (r < 0)
+                                return log_oom();
+                        break;
+
+                case ARG_MAKE_ENTRY_DIRECTORY:
+                        if (streq(optarg, "auto"))
+                                arg_make_entry_directory = -1;
+                        else {
+                                r = parse_boolean_argument("--make-entry-directory=", optarg, NULL);
+                                if (r < 0)
+                                        return r;
+
+                                arg_make_entry_directory = r;
+                        }
+                        break;
+
+                case ARG_ENTRY_TOKEN:
+                        r = parse_boot_entry_token_type(optarg, &c->entry_token_type, &c->entry_token);
+                        if (r < 0)
+                                return r;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached();
+                }
+
+        return 1;
+}
+
+static int run(int argc, char* argv[]) {
+        static const Verb verbs[] = {
+                { "add",         3,        VERB_ANY, 0,            verb_add            },
+                { "remove",      2,        2,        0,            verb_remove         },
+                { "inspect",     1,        2,        VERB_DEFAULT, verb_inspect        },
+                {}
+        };
+        _cleanup_(context_done) Context c = {
+                .rfd = -EBADF,
+                .action = _ACTION_INVALID,
+                .kernel_image_type = KERNEL_IMAGE_TYPE_UNKNOWN,
+                .layout = _LAYOUT_INVALID,
+                .entry_token_type = BOOT_ENTRY_TOKEN_AUTO,
+        };
+        int r;
+
+        log_setup();
+
+        if (bypass())
+                return 0;
+
+        r = parse_argv(argc, argv, &c);
+        if (r <= 0)
+                return r;
+
+        r = context_init(&c);
+        if (r < 0)
+                return r;
+
+        if (invoked_as(argv, "installkernel"))
+                return run_as_installkernel(argc, argv, &c);
+
+        return dispatch_verb(argc, argv, verbs, &c);
+}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/kernel-install/kernel-install.in b/src/kernel-install/kernel-install.in
deleted file mode 100755 (executable)
index 611f672..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-#!/bin/sh
-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
-# ex: ts=8 sw=4 sts=4 et filetype=sh
-# SPDX-License-Identifier: LGPL-2.1-or-later
-#
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <https://www.gnu.org/licenses/>.
-
-skip_remaining=77
-
-set -e
-
-usage()
-{
-    echo "Usage:"
-    echo "  kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE...]"
-    echo "  kernel-install [OPTIONS...] remove KERNEL-VERSION"
-    echo "  kernel-install [OPTIONS...] inspect"
-    echo "Options:"
-    echo "  -h, --help     Print this help and exit"
-    echo "      --version  Print version string and exit"
-    echo "  -v, --verbose  Increase verbosity"
-}
-
-dropindirs_sort()
-{
-    suffix="$1"
-    shift
-
-    for d; do
-        for i in "$d/"*"$suffix"; do
-            [ -e "$i" ] && echo "${i##*/}"
-        done
-    done | sort -Vu | while read -r f; do
-        for d; do
-            if [ -e "$d/$f" ]; then
-                [ -x "$d/$f" ] && echo "$d/$f"
-                continue 2
-            fi
-        done
-    done
-}
-
-export LC_COLLATE=C
-
-for i; do
-    if [ "$i" = "--help" ] || [ "$i" = "-h" ]; then
-        usage
-        exit 0
-    fi
-done
-
-for i; do
-    if [ "$i" = "--version" ]; then
-        echo "kernel-install {{PROJECT_VERSION}} ({{GIT_VERSION}})"
-        exit 0
-    fi
-done
-
-if [ "$KERNEL_INSTALL_BYPASS" = "1" ]; then
-    echo "kernel-install: Skipping execution because KERNEL_INSTALL_BYPASS=1"
-    exit 0
-fi
-
-export KERNEL_INSTALL_VERBOSE=0
-if [ "$1" = "--verbose" ] || [ "$1" = "-v" ]; then
-    shift
-    export KERNEL_INSTALL_VERBOSE=1
-    log_verbose() { printf "%s\n" "$*"; }
-else
-    log_verbose() { :; }
-fi
-
-if [ "${0##*/}" = "installkernel" ]; then
-    COMMAND=add
-    # kernel's install.sh invokes us as
-    #   /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
-    # We ignore the last two arguments.
-    set -- "${1:?}" "${2:?}"
-else
-    COMMAND="$1"
-    [ $# -ge 1 ] && shift
-fi
-
-if [ "$COMMAND" = "inspect" ]; then
-    KERNEL_VERSION=""
-else
-    if [ $# -lt 1 ]; then
-        echo "Error: not enough arguments" >&2
-        exit 1
-    fi
-
-    KERNEL_VERSION="$1"
-    shift
-fi
-
-# These three settings are only settable via install.conf
-layout=
-initrd_generator=
-uki_generator=
-# These two settings can be inherited from the environment
-_MACHINE_ID_SAVED="$MACHINE_ID"
-_BOOT_ROOT_SAVED="$BOOT_ROOT"
-
-if [ -n "$KERNEL_INSTALL_CONF_ROOT" ]; then
-    install_conf="$KERNEL_INSTALL_CONF_ROOT/install.conf"
-elif [ -f "/etc/kernel/install.conf" ]; then
-    install_conf="/etc/kernel/install.conf"
-elif [ -f "/usr/lib/kernel/install.conf" ]; then
-    install_conf="/usr/lib/kernel/install.conf"
-else
-    install_conf=
-fi
-
-if [ -f "$install_conf" ]; then
-    log_verbose "Reading $install_conf…"
-    # shellcheck source=/dev/null
-    . "$install_conf"
-fi
-
-[ -n "$layout" ] && log_verbose "$install_conf configures layout=$layout"
-[ -n "$initrd_generator" ] && \
-    log_verbose "$install_conf configures initrd_generator=$initrd_generator"
-[ -n "$uki_generator" ] && \
-    log_verbose "$install_conf configures uki_generator=$uki_generator"
-
-if [ -n "$_MACHINE_ID_SAVED" ]; then
-    MACHINE_ID="$_MACHINE_ID_SAVED"
-    log_verbose "MACHINE_ID=$MACHINE_ID set via environment"
-else
-    [ -n "$MACHINE_ID" ] && log_verbose "MACHINE_ID=$MACHINE_ID set via install.conf"
-fi
-
-if [ -n "$_BOOT_ROOT_SAVED" ]; then
-     BOOT_ROOT="$_BOOT_ROOT_SAVED"
-     log_verbose "BOOT_ROOT=$BOOT_ROOT set via environment"
-else
-    [ -n "$BOOT_ROOT" ] && log_verbose "BOOT_ROOT=$BOOT_ROOT set via install.conf"
-fi
-
-# If /etc/machine-id is initialized we'll use it, otherwise we'll use a freshly
-# generated one. If the user configured an explicit machine ID to use in
-# /etc/machine-info to use for our purpose, we'll use that instead (for
-# compatibility).
-# shellcheck source=/dev/null
-if [ -z "$MACHINE_ID" ] && [ -f /etc/machine-info ]; then
-    . /etc/machine-info
-    MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID"
-    [ -n "$MACHINE_ID" ] && \
-        log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-info"
-fi
-if [ -z "$MACHINE_ID" ] && [ -s /etc/machine-id ]; then
-    read -r MACHINE_ID </etc/machine-id
-    [ "$MACHINE_ID" = "uninitialized" ] && unset MACHINE_ID
-    [ -n "$MACHINE_ID" ] && \
-        log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-id"
-fi
-if [ -z "$MACHINE_ID" ]; then
-    MACHINE_ID="$(systemd-id128 new)" || exit 1
-    log_verbose "new machine-id $MACHINE_ID generated"
-fi
-
-# Now that we determined the machine ID to use, let's determine the "token" for
-# the boot loader entry to generate. We use that for naming the directory below
-# $BOOT where we want to place the kernel/initrd and related resources, as well
-# for naming the .conf boot loader spec entry. Typically this is just the
-# machine ID, but it can be anything else, too, if we are told so.
-ENTRY_TOKEN_FILE="${KERNEL_INSTALL_CONF_ROOT:-/etc/kernel}/entry-token"
-
-if [ -z "$ENTRY_TOKEN" ] && [ -f "$ENTRY_TOKEN_FILE" ]; then
-    read -r ENTRY_TOKEN <"$ENTRY_TOKEN_FILE"
-    log_verbose "entry-token \"$ENTRY_TOKEN\" acquired from $ENTRY_TOKEN_FILE"
-fi
-if [ -z "$ENTRY_TOKEN" ]; then
-    # If not configured explicitly, then use a few candidates: the machine ID,
-    # the IMAGE_ID= and ID= fields from /etc/os-release and finally the fixed
-    # string "Default"
-    ENTRY_TOKEN_SEARCH="$MACHINE_ID"
-    # shellcheck source=/dev/null
-    [ -f /etc/os-release ] && . /etc/os-release
-    [ -n "$IMAGE_ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $IMAGE_ID"
-    [ -n "$ID" ] && ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH $ID"
-    ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN_SEARCH Default"
-else
-    ENTRY_TOKEN_SEARCH="$ENTRY_TOKEN"
-fi
-log_verbose "Entry-token candidates: $ENTRY_TOKEN_SEARCH"
-
-# NB: The $MACHINE_ID is guaranteed to be a valid machine ID, but
-#     $ENTRY_TOKEN can be any string that fits into a VFAT filename, though
-#     typically is just the machine ID.
-
-if [ -n "$BOOT_ROOT" ]; then
-    # If this was already configured, don't try to guess
-    BOOT_ROOT_SEARCH="$BOOT_ROOT"
-else
-    BOOT_ROOT_SEARCH="/efi /boot /boot/efi"
-fi
-
-for pref in $BOOT_ROOT_SEARCH; do
-    for suff in $ENTRY_TOKEN_SEARCH; do
-        if [ -d "$pref/$suff" ]; then
-            [ -z "$BOOT_ROOT" ] && BOOT_ROOT="$pref"
-            [ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$suff"
-
-            log_verbose "$pref/$suff exists, using BOOT_ROOT=$BOOT_ROOT, ENTRY_TOKEN=$ENTRY_TOKEN"
-            break 2
-        else
-            log_verbose "$pref/$suff not found…"
-        fi
-    done
-
-    if [ -d "$pref/loader/entries" ]; then
-        [ -z "$BOOT_ROOT" ] && BOOT_ROOT="$pref"
-        log_verbose "$pref/loader/entries exists, using BOOT_ROOT=$BOOT_ROOT"
-        break
-    else
-        log_verbose "$pref/loader/entries not found…"
-    fi
-done
-
-[ -z "$BOOT_ROOT" ] && for pref in "/efi" "/boot/efi"; do
-    if mountpoint -q "$pref"; then
-        BOOT_ROOT="$pref"
-        log_verbose "$pref is a mount point, using BOOT_ROOT=$BOOT_ROOT"
-        break
-    else
-        log_verbose "$pref is not a mount point…"
-    fi
-done
-
-if [ -z "$BOOT_ROOT" ]; then
-    BOOT_ROOT="/boot"
-    log_verbose "KERNEL_INSTALL_BOOT_ROOT autodetection yielded no candidates, using \"$BOOT_ROOT\""
-fi
-
-if [ -z "$ENTRY_TOKEN" ]; then
-    ENTRY_TOKEN="$MACHINE_ID"
-    log_verbose "No entry-token candidate matched, using \"$ENTRY_TOKEN\" from machine-id"
-fi
-
-export KERNEL_INSTALL_IMAGE_TYPE=""
-if [ -f "$1" ]; then
-    KERNEL_INSTALL_IMAGE_TYPE="$(bootctl kernel-identify "$1" 2>/dev/null || echo "unknown")"
-fi
-
-if [ "$layout" = "auto" ] || [ -z "$layout" ]; then
-    # No layout configured by the administrator. Let's try to figure it out
-    # automatically from metadata already contained in $BOOT_ROOT.
-    if [ "$KERNEL_INSTALL_IMAGE_TYPE" = "uki" ]; then
-        layout="uki"
-        log_verbose "Kernel image is UKI, using layout=$layout"
-    elif [ -e "$BOOT_ROOT/loader/entries.srel" ]; then
-        read -r ENTRIES_SREL <"$BOOT_ROOT/loader/entries.srel"
-        if [ "$ENTRIES_SREL" = "type1" ]; then
-            # The loader/entries.srel file clearly indicates that the installed
-            # boot loader implements the proper standard upstream boot loader
-            # spec for Type #1 entries. Let's default to that, then.
-            layout="bls"
-        else
-            # The loader/entries.srel file indicates some other spec is
-            # implemented and owns the /loader/entries/ directory. Since we
-            # have no idea what that means, let's stay away from it by default.
-            layout="other"
-        fi
-        log_verbose "$BOOT_ROOT/loader/entries.srel with '$ENTRIES_SREL' found, using layout=$layout"
-
-    elif [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
-        # If the metadata in $BOOT_ROOT doesn't tell us anything, then check if
-        # the entry token directory already exists. If so, let's assume it's
-        # the standard boot loader spec, too.
-        layout="bls"
-
-        log_verbose "$BOOT_ROOT/$ENTRY_TOKEN exists, using layout=$layout"
-    else
-        # There's no metadata in $BOOT_ROOT, and apparently no entry token
-        # directory installed? Then we really don't know anything.
-        layout="other"
-
-        log_verbose "Entry-token directory not found, using layout=$layout"
-    fi
-fi
-
-ENTRY_DIR_ABS="$BOOT_ROOT/$ENTRY_TOKEN/$KERNEL_VERSION"
-log_verbose "Using ENTRY_DIR_ABS=$ENTRY_DIR_ABS"
-
-# Provide a directory where to store generated initrds
-cleanup() {
-    [ -n "$KERNEL_INSTALL_STAGING_AREA" ] && rm -rf "$KERNEL_INSTALL_STAGING_AREA"
-}
-
-trap cleanup EXIT
-
-KERNEL_INSTALL_STAGING_AREA="$(mktemp -d -t kernel-install.staging.XXXXXXX)"
-
-export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID"
-export KERNEL_INSTALL_ENTRY_TOKEN="$ENTRY_TOKEN"
-export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT"
-export KERNEL_INSTALL_LAYOUT="$layout"
-export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator"
-export KERNEL_INSTALL_UKI_GENERATOR="$uki_generator"
-export KERNEL_INSTALL_STAGING_AREA
-
-MAKE_ENTRY_DIR_ABS=0
-[ "$layout" = "bls" ] || MAKE_ENTRY_DIR_ABS=1
-
-ret=0
-
-if [ -z "$KERNEL_INSTALL_PLUGINS" ]; then
-    KERNEL_INSTALL_PLUGINS="$(
-        dropindirs_sort ".install" \
-            "/etc/kernel/install.d" \
-            "/usr/lib/kernel/install.d"
-    )"
-fi
-
-if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
-    printf '%s\n' "Plugin files:"
-    for f in $KERNEL_INSTALL_PLUGINS; do
-        printf '%s\n' "$f"
-    done
-fi
-
-case "$COMMAND" in
-    add)
-        if [ $# -lt 1 ]; then
-            echo "Error: command 'add' requires a kernel image" >&2
-            exit 1
-        fi
-
-        if ! [ -f "$1" ]; then
-            echo "Error: kernel image argument $1 not a file" >&2
-            exit 1
-        fi
-
-        if [ "$MAKE_ENTRY_DIR_ABS" -eq 0 ]; then
-            # Compatibility with earlier versions that used the presence of $BOOT_ROOT/$ENTRY_TOKEN
-            # to signal to 00-entry-directory to create $ENTRY_DIR_ABS
-            # to serve as the indication to use or to not use the BLS
-            if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
-                echo "+mkdir -v -p $ENTRY_DIR_ABS"
-                mkdir -v -p "$ENTRY_DIR_ABS" || exit 1
-            else
-                mkdir -p "$ENTRY_DIR_ABS" || exit 1
-            fi
-        fi
-
-        for f in $KERNEL_INSTALL_PLUGINS; do
-            log_verbose "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS" "$@"
-            err=0
-            "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@" || err=$?
-            [ $err -eq $skip_remaining ] && break
-            [ $err -ne 0 ] && exit $err
-        done
-        ;;
-
-    remove)
-        for f in $KERNEL_INSTALL_PLUGINS; do
-            log_verbose "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS"
-            err=0
-            "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS" || err=$?
-            [ $err -eq $skip_remaining ] && break
-            [ $err -ne 0 ] && exit $err
-        done
-
-        if [ "$MAKE_ENTRY_DIR_ABS" -eq 0 ]; then
-            log_verbose "Removing $ENTRY_DIR_ABS/"
-            rm -rf "$ENTRY_DIR_ABS"
-        fi
-        ;;
-
-    inspect)
-        echo "KERNEL_INSTALL_MACHINE_ID: $KERNEL_INSTALL_MACHINE_ID"
-        echo "KERNEL_INSTALL_ENTRY_TOKEN: $KERNEL_INSTALL_ENTRY_TOKEN"
-        echo "KERNEL_INSTALL_BOOT_ROOT: $KERNEL_INSTALL_BOOT_ROOT"
-        echo "KERNEL_INSTALL_LAYOUT: $KERNEL_INSTALL_LAYOUT"
-        echo "KERNEL_INSTALL_INITRD_GENERATOR: $KERNEL_INSTALL_INITRD_GENERATOR"
-        echo "KERNEL_INSTALL_UKI_GENERATOR: $KERNEL_INSTALL_UKI_GENERATOR"
-        echo "ENTRY_DIR_ABS: $KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN/\$KERNEL_VERSION"
-
-        # Assert that ENTRY_DIR_ABS actually matches what we are printing here
-        [ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; }
-        ;;
-
-    *)
-        echo "Error: unknown command '$COMMAND'" >&2
-        exit 1
-        ;;
-esac
-
-exit "$ret"
index 744071b9e94c021dc28f96ca6e63198ce0620ac9..6d568966d61f0fcbfa1501733a8618a810261d60 100644 (file)
@@ -1,7 +1,5 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
-kernel_install_in = files('kernel-install.in')
-
 ukify_install = custom_target(
         '60-ukify.install',
         input : '60-ukify.install.in',
index 4be877135973cf47dfa9cb08207c8e3214f8432f..edc67e46fb9b3c929b958c7bdcfec90bfd456499 100755 (executable)
@@ -63,6 +63,7 @@ grep -qE 'image' "$BOOT_ROOT/the-token/1.1.1/linux"
 grep -qE 'initrd' "$BOOT_ROOT/the-token/1.1.1/initrd"
 
 "$kernel_install" inspect
+"$kernel_install" inspect "$D/sources/linux"
 
 "$kernel_install" -v remove 1.1.1
 test ! -e "$entry"
@@ -148,3 +149,92 @@ if [ -x "$bootctl" ]; then
     test ! -e "$BOOT_ROOT/the-token/1.1.1/linux"
     test ! -e "$BOOT_ROOT/the-token/1.1.1/initrd"
 fi
+
+###########################################
+# tests for --make-entry-directory=
+###########################################
+
+# disable all dropins
+cat >"$D/00-skip.install" <<EOF
+#!/bin/bash
+exit 77
+EOF
+chmod +x "$D/00-skip.install"
+export KERNEL_INSTALL_PLUGINS="$D/00-skip.install"
+
+# drop layout= from install.conf
+cat >"$D/sources/install.conf" <<EOF
+initrd_generator=none
+# those are overridden by envvars
+BOOT_ROOT="$D/badboot"
+MACHINE_ID=badbadbadbadbadbad6abadbadbadbad
+EOF
+export KERNEL_INSTALL_CONF_ROOT="$D/sources"
+
+rm -rf "$BOOT_ROOT"
+mkdir -p "$BOOT_ROOT"
+
+# 1. defaults to 'auto', and the entry directory is created only when the layout is BLS
+# 1.1 token directory does not exist -> layout is other.
+"$kernel_install" -v add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+
+# 1.2 token directory exists -> layout is BLS
+mkdir -p "$BOOT_ROOT/the-token"
+"$kernel_install" -v add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test -d "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+rmdir "$BOOT_ROOT/the-token"
+
+# 2. --make-entry-directory=yes
+# 2.1 token directory does not exist -> layout is other.
+"$kernel_install" -v --make-entry-directory=yes add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test -d "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v --make-entry-directory=yes remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+test -d "$BOOT_ROOT/the-token"
+
+# 2.2 token directory exists -> layout is BLS
+mkdir -p "$BOOT_ROOT/the-token"
+"$kernel_install" -v --make-entry-directory=yes add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test -d "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v --make-entry-directory=yes remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+test -d "$BOOT_ROOT/the-token"
+rmdir "$BOOT_ROOT/the-token"
+
+# 3. --make-entry-directory=no
+# 3.1 token directory does not exist -> layout is other.
+"$kernel_install" -v --make-entry-directory=no add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v --make-entry-directory=no remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+
+# 3.2 token directory exists -> layout is BLS
+mkdir -p "$BOOT_ROOT/the-token"
+"$kernel_install" -v --make-entry-directory=no add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+"$kernel_install" -v --make-entry-directory=no remove 1.1.1
+test ! -e "$BOOT_ROOT/the-token/1.1.1"
+test -d "$BOOT_ROOT/the-token"
+rmdir "$BOOT_ROOT/the-token"
+
+###########################################
+# tests for --entry-token=
+###########################################
+"$kernel_install" -v --make-entry-directory=yes --entry-token=machine-id add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test -d "$BOOT_ROOT/$MACHINE_ID/1.1.1"
+"$kernel_install" -v --make-entry-directory=yes --entry-token=machine-id remove 1.1.1
+test ! -e "$BOOT_ROOT/$MACHINE_ID/1.1.1"
+test -d "$BOOT_ROOT/$MACHINE_ID"
+rmdir "$BOOT_ROOT/$MACHINE_ID"
+
+"$kernel_install" -v --make-entry-directory=yes --entry-token=literal:hoge add 1.1.1 "$D/sources/linux" "$D/sources/initrd"
+test -d "$BOOT_ROOT/hoge/1.1.1"
+"$kernel_install" -v --make-entry-directory=yes --entry-token=literal:hoge remove 1.1.1
+test ! -e "$BOOT_ROOT/hoge/1.1.1"
+test -d "$BOOT_ROOT/hoge"
+rmdir "$BOOT_ROOT/hoge"
index 936a3577f546e29f5f099df474c0030d0ccd77de..ea13e02719b86cc386fe41563675976419a4002e 100644 (file)
@@ -826,4 +826,5 @@ global:
         sd_pid_notify_barrier;
         sd_event_source_leave_ratelimit;
         sd_journal_step_one;
+        sd_session_get_leader;
 } LIBSYSTEMD_253;
index 987d151b55ebfde5787f34eadf977a40b5224ed8..a504437ac50f6249f9d7983f22d58423f1f9a815 100644 (file)
@@ -76,7 +76,7 @@ static void* thread_server(void *p) {
         assert_se(bind(fd, &u.sa, sa_len) >= 0);
         usleep(100 * USEC_PER_MSEC);
 
-        assert_se(listen(fd, SOMAXCONN) >= 0);
+        assert_se(listen(fd, SOMAXCONN_DELUXE) >= 0);
         usleep(100 * USEC_PER_MSEC);
 
         assert_se(touch(path) >= 0);
index c4472d204e6b3243715529809ea944fd901df496..5711e5e18a453f12da29cac271ae2969892e04cb 100644 (file)
@@ -466,7 +466,8 @@ static int pid_notify_with_fds_internal(
         struct cmsghdr *cmsg = NULL;
         const char *e;
         bool send_ucred;
-        int r;
+        ssize_t n;
+        int type, r;
 
         if (!state)
                 return -EINVAL;
@@ -491,30 +492,37 @@ static int pid_notify_with_fds_internal(
         if (address.sockaddr.vm.svm_family == AF_VSOCK && address.sockaddr.vm.svm_cid == VMADDR_CID_ANY)
                 return -EINVAL;
 
+        type = address.type == 0 ? SOCK_DGRAM : address.type;
+
         /* At the time of writing QEMU does not yet support AF_VSOCK + SOCK_DGRAM and returns
          * ENODEV. Fallback to SOCK_SEQPACKET in that case. */
-        fd = socket(address.sockaddr.sa.sa_family, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+        fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
         if (fd < 0) {
-                if (!(ERRNO_IS_NOT_SUPPORTED(errno) || errno == ENODEV) || address.sockaddr.sa.sa_family != AF_VSOCK)
-                        return log_debug_errno(errno, "Failed to open datagram notify socket to '%s': %m", e);
-
-                fd = socket(address.sockaddr.sa.sa_family, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
+                if (!(ERRNO_IS_NOT_SUPPORTED(errno) || errno == ENODEV) || address.sockaddr.sa.sa_family != AF_VSOCK || address.type > 0)
+                        return log_debug_errno(errno, "Failed to open %s notify socket to '%s': %m", socket_address_type_to_string(type), e);
+
+                type = SOCK_SEQPACKET;
+                fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
+                if (fd < 0 && ERRNO_IS_NOT_SUPPORTED(errno)) {
+                        type = SOCK_STREAM;
+                        fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
+                }
                 if (fd < 0)
-                        return log_debug_errno(errno, "Failed to open sequential packet socket to '%s': %m", e);
+                        return log_debug_errno(errno, "Failed to open %s socket to '%s': %m", socket_address_type_to_string(type), e);
+        }
 
+        if (address.sockaddr.sa.sa_family == AF_VSOCK) {
                 r = vsock_bind_privileged_port(fd);
                 if (r < 0 && !ERRNO_IS_PRIVILEGE(r))
                         return log_debug_errno(r, "Failed to bind socket to privileged port: %m");
+        }
 
+        if (IN_SET(type, SOCK_STREAM, SOCK_SEQPACKET)) {
                 if (connect(fd, &address.sockaddr.sa, address.size) < 0)
                         return log_debug_errno(errno, "Failed to connect socket to '%s': %m", e);
 
                 msghdr.msg_name = NULL;
                 msghdr.msg_namelen = 0;
-        } else if (address.sockaddr.sa.sa_family == AF_VSOCK) {
-                r = vsock_bind_privileged_port(fd);
-                if (r < 0 && !ERRNO_IS_PRIVILEGE(r))
-                        return log_debug_errno(r, "Failed to bind socket to privileged port: %m");
         }
 
         (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
@@ -560,21 +568,32 @@ static int pid_notify_with_fds_internal(
                 }
         }
 
-        /* First try with fake ucred data, as requested */
-        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0)
-                return 1;
-
-        /* If that failed, try with our own ucred instead */
-        if (send_ucred) {
-                msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
-                if (msghdr.msg_controllen == 0)
+        do {
+                /* First try with fake ucred data, as requested */
+                n = sendmsg(fd, &msghdr, MSG_NOSIGNAL);
+                if (n < 0) {
+                        if (!send_ucred)
+                                return log_debug_errno(errno, "Failed to send notify message to '%s': %m", e);
+
+                        /* If that failed, try with our own ucred instead */
+                        msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
+                        if (msghdr.msg_controllen == 0)
+                                msghdr.msg_control = NULL;
+
+                        n = 0;
+                        send_ucred = false;
+                } else {
+                        /* Unless we're using SOCK_STREAM, we expect to write all the contents immediately. */
+                        if (type != SOCK_STREAM && (size_t) n < IOVEC_TOTAL_SIZE(msghdr.msg_iov, msghdr.msg_iovlen))
+                                return -EIO;
+
+                        /* Make sure we only send fds and ucred once, even if we're using SOCK_STREAM. */
                         msghdr.msg_control = NULL;
+                        msghdr.msg_controllen = 0;
+                }
+        } while (!IOVEC_INCREMENT(msghdr.msg_iov, msghdr.msg_iovlen, n));
 
-                if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0)
-                        return 1;
-        }
-
-        return log_debug_errno(errno, "Failed to send notify message to '%s': %m", e);
+        return 1;
 }
 
 _public_ int sd_pid_notify_with_fds(
index 9c624ab56f779a0664d1012f7255b4679b6ca99a..aba458185b8378e5de0b47dadcf59383f23d964d 100644 (file)
@@ -62,7 +62,7 @@ static bool event_source_is_offline(sd_event_source *s) {
 static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
         [SOURCE_IO]                  = "io",
         [SOURCE_TIME_REALTIME]       = "realtime",
-        [SOURCE_TIME_BOOTTIME]       = "bootime",
+        [SOURCE_TIME_BOOTTIME]       = "boottime",
         [SOURCE_TIME_MONOTONIC]      = "monotonic",
         [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm",
         [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm",
index 957817bfabc4e624a7fa8d43dad90cc949149cbe..339ac265299350e654c17901e474f42ff4aea8bf 100644 (file)
@@ -43,6 +43,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "syslog-util.h"
+#include "uid-alloc-range.h"
 
 #define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
 
@@ -1322,25 +1323,32 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
 static bool file_type_wanted(int flags, const char *filename) {
         assert(filename);
 
-        if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
+        if (!ENDSWITH_SET(filename, ".journal", ".journal~"))
                 return false;
 
         /* no flags set → every type is OK */
         if (!(flags & (SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)))
                 return true;
 
-        if (flags & SD_JOURNAL_SYSTEM && file_has_type_prefix("system", filename))
-                return true;
-
-        if (flags & SD_JOURNAL_CURRENT_USER) {
+        if (FLAGS_SET(flags, SD_JOURNAL_CURRENT_USER)) {
                 char prefix[5 + DECIMAL_STR_MAX(uid_t) + 1];
 
-                xsprintf(prefix, "user-"UID_FMT, getuid());
+                xsprintf(prefix, "user-" UID_FMT, getuid());
 
                 if (file_has_type_prefix(prefix, filename))
                         return true;
+
+                /* If SD_JOURNAL_CURRENT_USER is specified and we are invoked under a system UID, then
+                 * automatically enable SD_JOURNAL_SYSTEM too, because journald will actually put system user
+                 * data into the system journal. */
+
+                if (uid_for_system_journal(getuid()))
+                        flags |= SD_JOURNAL_SYSTEM;
         }
 
+        if (FLAGS_SET(flags, SD_JOURNAL_SYSTEM) && file_has_type_prefix("system", filename))
+                return true;
+
         return false;
 }
 
index c5d54bbf74d238afd0c2b567a1ff98e4a7f781a7..4d09b156536c06a875749b6b804f00e83a6ac867 100644 (file)
@@ -870,6 +870,25 @@ _public_ int sd_session_get_remote_host(const char *session, char **remote_host)
         return session_get_string(session, "REMOTE_HOST", remote_host);
 }
 
+_public_ int sd_session_get_leader(const char *session, pid_t *leader) {
+        _cleanup_free_ char *leader_string = NULL;
+        pid_t pid;
+        int r;
+
+        assert_return(leader, -EINVAL);
+
+        r = session_get_string(session, "LEADER", &leader_string);
+        if (r < 0)
+                return r;
+
+        r = parse_pid(leader_string, &pid);
+        if (r < 0)
+                return r;
+
+        *leader = pid;
+        return 0;
+}
+
 _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
         _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
         int r;
index 132f63e57decbd021e48037ccfce2d3829cedc2d..9d1df723813c85dd5e4763d6445c5aaba08ff527 100644 (file)
@@ -45,13 +45,13 @@ static int netlink_new(sd_netlink **ret) {
                  * while the socket sticks around we might get confused by replies from earlier runs coming
                  * in late — which is pretty likely if we'd start our sequence numbers always from 1. Hence,
                  * let's start with a value based on the system clock. This should make collisions much less
-                 * likely (though still theoretically possible). We use a 32 bit µs counter starting at boot
+                 * likely (though still theoretically possible). We use a 32 bit μs counter starting at boot
                  * for this (and explicitly exclude the zero, see above). This counter will wrap around after
                  * a bit more than 1h, but that's hopefully OK as the kernel shouldn't take that long to
                  * reply to our requests.
                  *
                  * We only pick the initial start value this way. For each message we simply increase the
-                 * sequence number by 1. This means we could enqueue 1 netlink message per µs without risking
+                 * sequence number by 1. This means we could enqueue 1 netlink message per μs without risking
                  * collisions, which should be OK.
                  *
                  * Note this means the serials will be in the range 1…UINT32_MAX here.
index 43124b99ae87482cdf2d170a7ff68fde2d25e445..4c2d3173fbebb843fe71cd22c3e2d94b15d9dd9d 100644 (file)
@@ -76,7 +76,6 @@ TEST(message_getlink) {
         assert_se(sd_netlink_message_read_u32(reply, IFLA_GROUP, &u32_data) >= 0);
         assert_se(sd_netlink_message_read_u32(reply, IFLA_TXQLEN, &u32_data) >= 0);
         assert_se(sd_netlink_message_read_u32(reply, IFLA_NUM_TX_QUEUES, &u32_data) >= 0);
-        assert_se(sd_netlink_message_read_u32(reply, IFLA_NUM_RX_QUEUES, &u32_data) >= 0);
 
         /* string */
         assert_se(sd_netlink_message_read_string(reply, IFLA_IFNAME, &str_data) >= 0);
index fd90f3c72486c0520994f3f77bd319845e2cb852..a145e13ecd7ca6f7bf48d04ce311d7f7bdd9a5f1 100644 (file)
@@ -13,11 +13,11 @@ ko                  kr      pc105           -               terminate:ctrl_alt_bksp
 ro-std                 ro      pc105           std             terminate:ctrl_alt_bksp
 de-latin1              de      pc105           -               terminate:ctrl_alt_bksp
 slovene                        si      pc105           -               terminate:ctrl_alt_bksp
-hu101                  hu      pc105           qwerty          terminate:ctrl_alt_bksp
+hu                     hu      pc105           -               terminate:ctrl_alt_bksp
 jp106                  jp      jp106           -               terminate:ctrl_alt_bksp
 croat                  hr      pc105           -               terminate:ctrl_alt_bksp
 it2                    it      pc105           -               terminate:ctrl_alt_bksp
-hu                     hu      pc105           -               terminate:ctrl_alt_bksp
+hu101                  hu      pc105           qwerty          terminate:ctrl_alt_bksp
 sr-latin               rs      pc105           latin           terminate:ctrl_alt_bksp
 fi                     fi      pc105           -               terminate:ctrl_alt_bksp
 fr_CH                  ch      pc105           fr              terminate:ctrl_alt_bksp
index e1e9b723c8c0129b7c472bc95b98fc7196400c6d..79531d2cc491091e84d490d0c7ad59fb983f4168 100644 (file)
@@ -2871,7 +2871,7 @@ static int method_set_reboot_to_boot_loader_menu(
                 } else {
                         char buf[DECIMAL_STR_MAX(uint64_t) + 1];
 
-                        xsprintf(buf, "%" PRIu64, x); /* µs granularity */
+                        xsprintf(buf, "%" PRIu64, x); /* μs granularity */
 
                         r = write_string_file_atomic_label("/run/systemd/reboot-to-boot-loader-menu", buf);
                         if (r < 0)
index 9a665bd95946b0b87df6c495a84d3affcc65235c..8a3c9e0165fd69e450621f058ec8b0e04fe77e11 100644 (file)
@@ -19,4 +19,5 @@ session  required   pam_namespace.so
 {% if ENABLE_HOMED %}
 -session optional   pam_systemd_home.so
 {% endif %}
+session  optional   pam_umask.so silent
 session  optional   pam_systemd.so
index f54e955caea81cb255c0b6fd2bcde851cd6954c6..ab61184d9f914332c6e7f2df36b476b068996e3d 100644 (file)
@@ -5564,13 +5564,13 @@ static int run(int argc, char *argv[]) {
 
                         {
                                 BLOCK_SIGNALS(SIGINT);
-                                r = btrfs_subvol_snapshot(arg_directory, np,
-                                                          (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
-                                                          BTRFS_SNAPSHOT_FALLBACK_COPY |
-                                                          BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
-                                                          BTRFS_SNAPSHOT_RECURSIVE |
-                                                          BTRFS_SNAPSHOT_QUOTA |
-                                                          BTRFS_SNAPSHOT_SIGINT);
+                                r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np,
+                                                             (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+                                                             BTRFS_SNAPSHOT_FALLBACK_COPY |
+                                                             BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+                                                             BTRFS_SNAPSHOT_RECURSIVE |
+                                                             BTRFS_SNAPSHOT_QUOTA |
+                                                             BTRFS_SNAPSHOT_SIGINT);
                         }
                         if (r == -EINTR) {
                                 log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np);
@@ -5605,14 +5605,14 @@ static int run(int argc, char *argv[]) {
 
                                 {
                                         BLOCK_SIGNALS(SIGINT);
-                                        r = btrfs_subvol_snapshot(arg_template, arg_directory,
-                                                                  (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
-                                                                  BTRFS_SNAPSHOT_FALLBACK_COPY |
-                                                                  BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
-                                                                  BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
-                                                                  BTRFS_SNAPSHOT_RECURSIVE |
-                                                                  BTRFS_SNAPSHOT_QUOTA |
-                                                                  BTRFS_SNAPSHOT_SIGINT);
+                                        r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_template, AT_FDCWD, arg_directory,
+                                                                     (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+                                                                     BTRFS_SNAPSHOT_FALLBACK_COPY |
+                                                                     BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+                                                                     BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+                                                                     BTRFS_SNAPSHOT_RECURSIVE |
+                                                                     BTRFS_SNAPSHOT_QUOTA |
+                                                                     BTRFS_SNAPSHOT_SIGINT);
                                 }
                                 if (r == -EEXIST)
                                         log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
index 89f7211bfd57ca20d967f6e47a3acee6d5b3d99d..634eb2e50cc029df1a2b90dab72e0ccaaf4c0db8 100644 (file)
@@ -152,6 +152,7 @@ static size_t arg_n_defer_partitions = 0;
 static uint64_t arg_sector_size = 0;
 static ImagePolicy *arg_image_policy = NULL;
 static Architecture arg_architecture = _ARCHITECTURE_INVALID;
+static int arg_offline = -1;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@@ -3154,29 +3155,78 @@ static int context_wipe_and_discard(Context *context) {
         return 0;
 }
 
+typedef struct DecryptedPartitionTarget {
+        int fd;
+        char *dm_name;
+        char *volume;
+        struct crypt_device *device;
+} DecryptedPartitionTarget;
+
+static DecryptedPartitionTarget* decrypted_partition_target_free(DecryptedPartitionTarget *t) {
+#ifdef HAVE_LIBCRYPTSETUP
+        int r;
+
+        if (!t)
+                return NULL;
+
+        safe_close(t->fd);
+
+        /* udev or so might access out block device in the background while we are done. Let's hence
+         * force detach the volume. We sync'ed before, hence this should be safe. */
+        r = sym_crypt_deactivate_by_name(t->device, t->dm_name, CRYPT_DEACTIVATE_FORCE);
+        if (r < 0)
+                log_warning_errno(r, "Failed to deactivate LUKS device, ignoring: %m");
+
+        sym_crypt_free(t->device);
+        free(t->dm_name);
+        free(t->volume);
+        free(t);
+#endif
+        return NULL;
+}
+
 typedef struct {
         LoopDevice *loop;
         int fd;
         char *path;
         int whole_fd;
+        DecryptedPartitionTarget *decrypted;
 } PartitionTarget;
 
 static int partition_target_fd(PartitionTarget *t) {
         assert(t);
         assert(t->loop || t->fd >= 0 || t->whole_fd >= 0);
-        return t->loop ? t->loop->fd : t->fd >= 0 ?  t->fd : t->whole_fd;
+
+        if (t->decrypted)
+                return t->decrypted->fd;
+
+        if (t->loop)
+                return t->loop->fd;
+
+        if (t->fd >= 0)
+                return t->fd;
+
+        return t->whole_fd;
 }
 
 static const char* partition_target_path(PartitionTarget *t) {
         assert(t);
         assert(t->loop || t->path);
-        return t->loop ? t->loop->node : t->path;
+
+        if (t->decrypted)
+                return t->decrypted->volume;
+
+        if (t->loop)
+                return t->loop->node;
+
+        return t->path;
 }
 
 static PartitionTarget *partition_target_free(PartitionTarget *t) {
         if (!t)
                 return NULL;
 
+        decrypted_partition_target_free(t->decrypted);
         loop_device_unref(t->loop);
         safe_close(t->fd);
         unlink_and_free(t->path);
@@ -3253,13 +3303,17 @@ static int partition_target_prepare(
         /* Loopback block devices are not only useful to turn regular files into block devices, but
          * also to cut out sections of block devices into new block devices. */
 
-        r = loop_device_make(whole_fd, O_RDWR, p->offset, size, 0, 0, LOCK_EX, &d);
-        if (r < 0 && r != -ENOENT && !ERRNO_IS_PRIVILEGE(r))
-                return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
-        if (r >= 0) {
-                t->loop = TAKE_PTR(d);
-                *ret = TAKE_PTR(t);
-                return 0;
+        if (arg_offline <= 0) {
+                r = loop_device_make(whole_fd, O_RDWR, p->offset, size, 0, 0, LOCK_EX, &d);
+                if (r < 0 && (arg_offline == 0 || (r != -ENOENT && !ERRNO_IS_PRIVILEGE(r))))
+                        return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
+                if (r >= 0) {
+                        t->loop = TAKE_PTR(d);
+                        *ret = TAKE_PTR(t);
+                        return 0;
+                }
+
+                log_debug_errno(r, "No access to loop devices, falling back to a regular file");
         }
 
         /* If we can't allocate a loop device, let's write to a regular file that we copy into the final
@@ -3267,8 +3321,6 @@ static int partition_target_prepare(
          * reflinking support, we can take advantage of this and just reflink the result into the image.
          */
 
-        log_debug_errno(r, "No access to loop devices, falling back to a regular file");
-
         r = prepare_temporary_file(t, size);
         if (r < 0)
                 return r;
@@ -3282,6 +3334,7 @@ static int partition_target_grow(PartitionTarget *t, uint64_t size) {
         int r;
 
         assert(t);
+        assert(!t->decrypted);
 
         if (t->loop) {
                 r = loop_device_refresh_size(t->loop, UINT64_MAX, size);
@@ -3305,6 +3358,9 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget
 
         assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
 
+        if (t->decrypted && fsync(t->decrypted->fd) < 0)
+                return log_error_errno(errno, "Failed to sync changes to '%s': %m", t->decrypted->volume);
+
         if (t->loop) {
                 r = loop_device_sync(t->loop);
                 if (r < 0)
@@ -3337,12 +3393,13 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget
         return 0;
 }
 
-static int partition_encrypt(Context *context, Partition *p, const char *node) {
+static int partition_encrypt(Context *context, Partition *p, PartitionTarget *target, bool offline) {
 #if HAVE_LIBCRYPTSETUP && HAVE_CRYPT_SET_DATA_OFFSET && HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE && HAVE_CRYPT_REENCRYPT
+        const char *node = partition_target_path(target);
         struct crypt_params_luks2 luks_params = {
                 .label = strempty(ASSERT_PTR(p)->new_label),
                 .sector_size = ASSERT_PTR(context)->sector_size,
-                .data_device = node,
+                .data_device = offline ? node : NULL,
         };
         struct crypt_params_reencrypt reencrypt_params = {
                 .mode = CRYPT_REENCRYPT_ENCRYPT,
@@ -3355,7 +3412,7 @@ static int partition_encrypt(Context *context, Partition *p, const char *node) {
         _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
         _cleanup_(erase_and_freep) char *base64_encoded = NULL;
         _cleanup_fclose_ FILE *h = NULL;
-        _cleanup_free_ char *hp = NULL;
+        _cleanup_free_ char *hp = NULL, *vol = NULL, *dm_name = NULL;
         const char *passphrase = NULL;
         size_t passphrase_size = 0;
         const char *vt;
@@ -3371,39 +3428,51 @@ static int partition_encrypt(Context *context, Partition *p, const char *node) {
 
         log_info("Encrypting future partition %" PRIu64 "...", p->partno);
 
-        r = var_tmp_dir(&vt);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine temporary files directory: %m");
+        if (offline) {
+                r = var_tmp_dir(&vt);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine temporary files directory: %m");
 
-        r = fopen_temporary_child(vt, &h, &hp);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create temporary LUKS header file: %m");
+                r = fopen_temporary_child(vt, &h, &hp);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create temporary LUKS header file: %m");
 
-        /* Weird cryptsetup requirement which requires the header file to be the size of at least one sector. */
-        r = ftruncate(fileno(h), context->sector_size);
-        if (r < 0)
-                return log_error_errno(r, "Failed to grow temporary LUKS header file: %m");
+                /* Weird cryptsetup requirement which requires the header file to be the size of at least one
+                 * sector. */
+                r = ftruncate(fileno(h), context->sector_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to grow temporary LUKS header file: %m");
+        } else {
+                if (asprintf(&dm_name, "luks-repart-%08" PRIx64, random_u64()) < 0)
+                        return log_oom();
 
-        r = sym_crypt_init(&cd, hp);
+                vol = path_join("/dev/mapper/", dm_name);
+                if (!vol)
+                        return log_oom();
+        }
+
+        r = sym_crypt_init(&cd, offline ? hp : node);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", hp);
 
         cryptsetup_enable_logging(cd);
 
-        /* Disable kernel keyring usage by libcryptsetup as a workaround for
-         * https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/273. This makes sure that we can do
-         * offline encryption even when repart is running in a container. */
-        r = sym_crypt_volume_key_keyring(cd, false);
-        if (r < 0)
-                return log_error_errno(r, "Failed to disable kernel keyring: %m");
+        if (offline) {
+                /* Disable kernel keyring usage by libcryptsetup as a workaround for
+                 * https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/273. This makes sure that we can
+                 * do offline encryption even when repart is running in a container. */
+                r = sym_crypt_volume_key_keyring(cd, false);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to disable kernel keyring: %m");
 
-        r = sym_crypt_metadata_locking(cd, false);
-        if (r < 0)
-                return log_error_errno(r, "Failed to disable metadata locking: %m");
+                r = sym_crypt_metadata_locking(cd, false);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to disable metadata locking: %m");
 
-        r = sym_crypt_set_data_offset(cd, LUKS2_METADATA_SIZE / 512);
-        if (r < 0)
-                return log_error_errno(r, "Failed to set data offset: %m");
+                r = sym_crypt_set_data_offset(cd, LUKS2_METADATA_SIZE / 512);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set data offset: %m");
+        }
 
         r = sym_crypt_format(cd,
                          CRYPT_LUKS2,
@@ -3514,51 +3583,85 @@ static int partition_encrypt(Context *context, Partition *p, const char *node) {
 #endif
         }
 
-        r = sym_crypt_reencrypt_init_by_passphrase(
-                        cd,
-                        NULL,
-                        passphrase,
-                        passphrase_size,
-                        CRYPT_ANY_SLOT,
-                        0,
-                        sym_crypt_get_cipher(cd),
-                        sym_crypt_get_cipher_mode(cd),
-                        &reencrypt_params);
-        if (r < 0)
-                return log_error_errno(r, "Failed to prepare for reencryption: %m");
+        if (offline) {
+                r = sym_crypt_reencrypt_init_by_passphrase(
+                                cd,
+                                NULL,
+                                passphrase,
+                                passphrase_size,
+                                CRYPT_ANY_SLOT,
+                                0,
+                                sym_crypt_get_cipher(cd),
+                                sym_crypt_get_cipher_mode(cd),
+                                &reencrypt_params);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to prepare for reencryption: %m");
 
-        /* crypt_reencrypt_init_by_passphrase() doesn't actually put the LUKS header at the front, we have
-         * to do that ourselves. */
+                /* crypt_reencrypt_init_by_passphrase() doesn't actually put the LUKS header at the front, we
+                 * have to do that ourselves. */
 
-        sym_crypt_free(cd);
-        cd = NULL;
+                sym_crypt_free(cd);
+                cd = NULL;
 
-        r = sym_crypt_init(&cd, node);
-        if (r < 0)
-                return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
+                r = sym_crypt_init(&cd, node);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
 
-        r = sym_crypt_header_restore(cd, CRYPT_LUKS2, hp);
-        if (r < 0)
-                return log_error_errno(r, "Failed to place new LUKS header at head of %s: %m", node);
+                r = sym_crypt_header_restore(cd, CRYPT_LUKS2, hp);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to place new LUKS header at head of %s: %m", node);
 
-        reencrypt_params.flags &= ~CRYPT_REENCRYPT_INITIALIZE_ONLY;
+                reencrypt_params.flags &= ~CRYPT_REENCRYPT_INITIALIZE_ONLY;
 
-        r = sym_crypt_reencrypt_init_by_passphrase(
-                        cd,
-                        NULL,
-                        passphrase,
-                        passphrase_size,
-                        CRYPT_ANY_SLOT,
-                        0,
-                        NULL,
-                        NULL,
-                        &reencrypt_params);
-        if (r < 0)
-                return log_error_errno(r, "Failed to load reencryption context: %m");
+                r = sym_crypt_reencrypt_init_by_passphrase(
+                                cd,
+                                NULL,
+                                passphrase,
+                                passphrase_size,
+                                CRYPT_ANY_SLOT,
+                                0,
+                                NULL,
+                                NULL,
+                                &reencrypt_params);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to load reencryption context: %m");
 
-        r = sym_crypt_reencrypt(cd, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Failed to encrypt %s: %m", node);
+                r = sym_crypt_reencrypt(cd, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to encrypt %s: %m", node);
+        } else {
+                _cleanup_free_ DecryptedPartitionTarget *t = NULL;
+                _cleanup_close_ int dev_fd = -1;
+
+                r = sym_crypt_activate_by_volume_key(
+                                cd,
+                                dm_name,
+                                NULL,
+                                VOLUME_KEY_SIZE,
+                                arg_discard ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to activate LUKS superblock: %m");
+
+                dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
+                if (dev_fd < 0)
+                        return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
+
+                if (flock(dev_fd, LOCK_EX) < 0)
+                        return log_error_errno(errno, "Failed to lock '%s': %m", vol);
+
+                t = new(DecryptedPartitionTarget, 1);
+                if (!t)
+                        return log_oom();
+
+                *t = (DecryptedPartitionTarget) {
+                        .fd = TAKE_FD(dev_fd),
+                        .dm_name = TAKE_PTR(dm_name),
+                        .volume = TAKE_PTR(vol),
+                        .device = TAKE_PTR(cd),
+                };
+
+                target->decrypted = TAKE_PTR(t);
+        }
 
         log_info("Successfully encrypted future partition %" PRIu64 ".", p->partno);
 
@@ -3830,6 +3933,12 @@ static int context_copy_blocks(Context *context) {
                 if (r < 0)
                         return r;
 
+                if (p->encrypt != ENCRYPT_OFF && t->loop) {
+                        r = partition_encrypt(context, p, t, /* offline = */ false);
+                        if (r < 0)
+                                return r;
+                }
+
                 log_info("Copying in '%s' (%s) on block level into future partition %" PRIu64 ".",
                          p->copy_blocks_path, FORMAT_BYTES(p->copy_blocks_size), p->partno);
 
@@ -3837,8 +3946,10 @@ static int context_copy_blocks(Context *context) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path);
 
-                if (p->encrypt != ENCRYPT_OFF) {
-                        r = partition_encrypt(context, p, partition_target_path(t));
+                log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path);
+
+                if (p->encrypt != ENCRYPT_OFF && !t->loop) {
+                        r = partition_encrypt(context, p, t, /* offline = */ true);
                         if (r < 0)
                                 return r;
                 }
@@ -3847,8 +3958,6 @@ static int context_copy_blocks(Context *context) {
                 if (r < 0)
                         return r;
 
-                log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path);
-
                 if (p->siblings[VERITY_HASH] && !partition_defer(p->siblings[VERITY_HASH])) {
                         r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
                                                          /* node = */ NULL, partition_target_path(t));
@@ -4070,14 +4179,14 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
                                                 sfd, ".",
                                                 pfd, fn,
                                                 UID_INVALID, GID_INVALID,
-                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
+                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
                                                 denylist);
                         } else
                                 r = copy_tree_at(
                                                 sfd, ".",
                                                 tfd, ".",
                                                 UID_INVALID, GID_INVALID,
-                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
+                                                COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE,
                                                 denylist);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m",
@@ -4110,7 +4219,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
                         if (tfd < 0)
                                 return log_error_errno(errno, "Failed to create target file '%s': %m", *target);
 
-                        r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_SIGINT);
+                        r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_SIGINT|COPY_TRUNCATE);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
 
@@ -4267,6 +4376,16 @@ static int context_mkfs(Context *context) {
                 if (r < 0)
                         return r;
 
+                if (p->encrypt != ENCRYPT_OFF && t->loop) {
+                        r = partition_target_grow(t, p->new_size);
+                        if (r < 0)
+                                return r;
+
+                        r = partition_encrypt(context, p, t, /* offline = */ false);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to encrypt device: %m");
+                }
+
                 log_info("Formatting future partition %" PRIu64 ".", p->partno);
 
                 /* If we're not writing to a loop device or if we're populating a read-only filesystem, we
@@ -4302,17 +4421,17 @@ static int context_mkfs(Context *context) {
                 if (partition_needs_populate(p) && !root) {
                         assert(t->loop);
 
-                        r = partition_populate_filesystem(context, p, t->loop->node);
+                        r = partition_populate_filesystem(context, p, partition_target_path(t));
                         if (r < 0)
                                 return r;
                 }
 
-                if (p->encrypt != ENCRYPT_OFF) {
+                if (p->encrypt != ENCRYPT_OFF && !t->loop) {
                         r = partition_target_grow(t, p->new_size);
                         if (r < 0)
                                 return r;
 
-                        r = partition_encrypt(context, p, partition_target_path(t));
+                        r = partition_encrypt(context, p, t, /* offline = */ true);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to encrypt device: %m");
                 }
@@ -4923,7 +5042,7 @@ static int context_split(Context *context) {
                 if (lseek(fd, p->offset, SEEK_SET) < 0)
                         return log_error_errno(errno, "Failed to seek to partition offset: %m");
 
-                r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES);
+                r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES|COPY_TRUNCATE);
                 if (r < 0)
                         return log_error_errno(r, "Failed to copy to split partition %s: %m", p->split_path);
         }
@@ -5852,6 +5971,7 @@ static int help(void) {
                "                          but don't populate them yet\n"
                "     --sector-size=SIZE   Set the logical sector size for the image\n"
                "     --architecture=ARCH  Set the generic architecture for the image\n"
+               "     --offline=BOOL       Whether to build the image offline\n"
                "\nSee the %s for details.\n",
                program_invocation_short_name,
                ansi_highlight(),
@@ -5894,6 +6014,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_SECTOR_SIZE,
                 ARG_SKIP_PARTITIONS,
                 ARG_ARCHITECTURE,
+                ARG_OFFLINE,
         };
 
         static const struct option options[] = {
@@ -5927,6 +6048,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "defer-partitions",     required_argument, NULL, ARG_DEFER_PARTITIONS     },
                 { "sector-size",          required_argument, NULL, ARG_SECTOR_SIZE          },
                 { "architecture",         required_argument, NULL, ARG_ARCHITECTURE         },
+                { "offline",              required_argument, NULL, ARG_OFFLINE              },
                 {}
         };
 
@@ -6235,6 +6357,19 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_architecture = r;
                         break;
 
+                case ARG_OFFLINE:
+                        if (streq(optarg, "auto"))
+                                arg_offline = -1;
+                        else {
+                                r = parse_boolean_argument("--offline=", optarg, NULL);
+                                if (r < 0)
+                                        return r;
+
+                                arg_offline = r;
+                        }
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
index 1c31377567812812fb1026938fe306653ad64b2b..52b8a5ba83141b54047f6bd6fc791cf511e22f2a 100644 (file)
@@ -255,6 +255,7 @@ static int extract_now(
                         _cleanup_(portable_metadata_unrefp) PortableMetadata *m = NULL;
                         _cleanup_(mac_selinux_freep) char *con = NULL;
                         _cleanup_close_ int fd = -EBADF;
+                        struct stat st;
 
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
@@ -275,6 +276,17 @@ static int extract_now(
                                 continue;
                         }
 
+                        /* Reject empty files, just in case */
+                        if (fstat(fd, &st) < 0) {
+                                log_debug_errno(errno, "Failed to stat unit file '%s', ignoring: %m", de->d_name);
+                                continue;
+                        }
+
+                        if (st.st_size <= 0) {
+                                log_debug("Unit file '%s' is empty, ignoring.", de->d_name);
+                                continue;
+                        }
+
 #if HAVE_SELINUX
                         /* The units will be copied on the host's filesystem, so if they had a SELinux label
                          * we have to preserve it. Copy it out so that it can be applied later. */
@@ -1130,7 +1142,7 @@ static int install_chroot_dropin(
                         }
         }
 
-        r = write_string_file(dropin, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+        r = write_string_file(dropin, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_SYNC);
         if (r < 0)
                 return log_debug_errno(r, "Failed to write '%s': %m", dropin);
 
@@ -1177,7 +1189,7 @@ static int install_profile_dropin(
 
         if (flags & PORTABLE_PREFER_COPY) {
 
-                r = copy_file_atomic(from, dropin, 0644, COPY_REFLINK);
+                r = copy_file_atomic(from, dropin, 0644, COPY_REFLINK|COPY_FSYNC);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), dropin);
 
@@ -1295,7 +1307,7 @@ static int attach_unit_file(
                 if (fchmod(fd, 0644) < 0)
                         return log_debug_errno(errno, "Failed to change unit file access mode for '%s': %m", path);
 
-                r = link_tmpfile(fd, tmp, path, /* replace= */ false);
+                r = link_tmpfile(fd, tmp, path, LINK_TMPFILE_SYNC);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to install unit file '%s': %m", path);
 
index e65fbbcbab36acc1a5400a7a4195b70b650e5281..c7ec3de588d1c83883ff51746e2098a698a8a633 100644 (file)
@@ -2586,34 +2586,6 @@ static int verb_log_level(int argc, char *argv[], void *userdata) {
         return verb_log_control_common(bus, "org.freedesktop.resolve1", argv[0], argc == 2 ? argv[1] : NULL);
 }
 
-static int monitor_rkey_from_json(JsonVariant *v, DnsResourceKey **ret_key) {
-        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
-        uint16_t type = 0, class = 0;
-        const char *name = NULL;
-        int r;
-
-        JsonDispatch dispatch_table[] = {
-                { "class", JSON_VARIANT_INTEGER, json_dispatch_uint16,       PTR_TO_SIZE(&class), JSON_MANDATORY },
-                { "type",  JSON_VARIANT_INTEGER, json_dispatch_uint16,       PTR_TO_SIZE(&type),  JSON_MANDATORY },
-                { "name",  JSON_VARIANT_STRING,  json_dispatch_const_string, PTR_TO_SIZE(&name),  JSON_MANDATORY },
-                {}
-        };
-
-        assert(v);
-        assert(ret_key);
-
-        r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
-        if (r < 0)
-                return r;
-
-        key = dns_resource_key_new(class, type, name);
-        if (!key)
-                return -ENOMEM;
-
-        *ret_key = TAKE_PTR(key);
-        return 0;
-}
-
 static int print_question(char prefix, const char *color, JsonVariant *question) {
         JsonVariant *q = NULL;
         int r;
@@ -2624,7 +2596,7 @@ static int print_question(char prefix, const char *color, JsonVariant *question)
                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
                 char buf[DNS_RESOURCE_KEY_STRING_MAX];
 
-                r = monitor_rkey_from_json(q, &key);
+                r = dns_resource_key_from_json(q, &key);
                 if (r < 0) {
                         log_warning_errno(r, "Received monitor message with invalid question key, ignoring: %m");
                         continue;
@@ -2807,6 +2779,157 @@ static int verb_monitor(int argc, char *argv[], void *userdata) {
         return c;
 }
 
+static int dump_cache_item(JsonVariant *item) {
+
+        struct item_info {
+                JsonVariant *key;
+                JsonVariant *rrs;
+                const char *type;
+                uint64_t until;
+        } item_info = {};
+
+        static const JsonDispatch dispatch_table[] = {
+                { "key",   JSON_VARIANT_OBJECT,   json_dispatch_variant_noref, offsetof(struct item_info, key),   JSON_MANDATORY },
+                { "rrs",   JSON_VARIANT_ARRAY,    json_dispatch_variant_noref, offsetof(struct item_info, rrs),   0              },
+                { "type",  JSON_VARIANT_STRING,   json_dispatch_const_string,  offsetof(struct item_info, type),  0              },
+                { "until", JSON_VARIANT_UNSIGNED, json_dispatch_uint64,        offsetof(struct item_info, until), 0              },
+                {},
+        };
+
+        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
+        int r, c = 0;
+
+        r = json_dispatch(item, dispatch_table, NULL, JSON_LOG, &item_info);
+        if (r < 0)
+                return r;
+
+        r = dns_resource_key_from_json(item_info.key, &k);
+        if (r < 0)
+                return log_error_errno(r, "Failed to turn JSON data to resource key: %m");
+
+        if (item_info.type)
+                printf("%s %s%s%s\n", DNS_RESOURCE_KEY_TO_STRING(k), ansi_highlight_red(), item_info.type, ansi_normal());
+        else {
+                JsonVariant *i;
+
+                JSON_VARIANT_ARRAY_FOREACH(i, item_info.rrs) {
+                        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+                        _cleanup_free_ void *data = NULL;
+                        JsonVariant *raw;
+                        size_t size;
+
+                        raw = json_variant_by_key(i, "raw");
+                        if (!raw)
+                                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "raw field missing from RR JSON data.");
+
+                        r = json_variant_unbase64(raw, &data, &size);
+                        if (r < 0)
+                                return log_error_errno(r, "Unable to decode raw RR JSON data: %m");
+
+                        r = dns_resource_record_new_from_raw(&rr, data, size);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse DNS data: %m");
+
+                        printf("%s\n", dns_resource_record_to_string(rr));
+                        c++;
+                }
+        }
+
+        return c;
+}
+
+static int dump_cache_scope(JsonVariant *scope) {
+
+        struct scope_info {
+                const char *protocol;
+                int family;
+                int ifindex;
+                const char *ifname;
+                JsonVariant *cache;
+        } scope_info = {
+                .family = AF_UNSPEC,
+        };
+        JsonVariant *i;
+        int r, c = 0;
+
+        static const JsonDispatch dispatch_table[] = {
+                { "protocol", JSON_VARIANT_STRING,  json_dispatch_const_string,  offsetof(struct scope_info, protocol), JSON_MANDATORY },
+                { "family",   JSON_VARIANT_INTEGER, json_dispatch_int,           offsetof(struct scope_info, family),   0              },
+                { "ifindex",  JSON_VARIANT_INTEGER, json_dispatch_int,           offsetof(struct scope_info, ifindex),  0              },
+                { "ifname",   JSON_VARIANT_STRING,  json_dispatch_const_string,  offsetof(struct scope_info, ifname),   0              },
+                { "cache",    JSON_VARIANT_ARRAY,   json_dispatch_variant_noref, offsetof(struct scope_info, cache),    JSON_MANDATORY },
+                {},
+        };
+
+        r = json_dispatch(scope, dispatch_table, NULL, JSON_LOG, &scope_info);
+        if (r < 0)
+                return r;
+
+        printf("%sScope protocol=%s", ansi_underline(), scope_info.protocol);
+
+        if (scope_info.family != AF_UNSPEC)
+                printf(" family=%s", af_to_name(scope_info.family));
+
+        if (scope_info.ifindex > 0)
+                printf(" ifindex=%i", scope_info.ifindex);
+        if (scope_info.ifname)
+                printf(" ifname=%s", scope_info.ifname);
+
+        printf("%s\n", ansi_normal());
+
+        JSON_VARIANT_ARRAY_FOREACH(i, scope_info.cache) {
+                r = dump_cache_item(i);
+                if (r < 0)
+                        return r;
+
+                c += r;
+        }
+
+        if (c == 0)
+                printf("%sNo entries.%s\n\n", ansi_grey(), ansi_normal());
+        else
+                printf("\n");
+
+        return 0;
+}
+
+static int verb_show_cache(int argc, char *argv[], void *userdata) {
+        _cleanup_(json_variant_unrefp) JsonVariant *d = NULL, *reply = NULL;
+        _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+        int r;
+
+        r = varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
+
+        r = varlink_call(vl, "io.systemd.Resolve.Monitor.DumpCache", NULL, &reply, NULL, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to issue DumpCache() varlink call: %m");
+
+        d = json_variant_by_key(reply, "dump");
+        if (!d)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "DumpCache() response is missing 'dump' key.");
+
+        if (!json_variant_is_array(d))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "DumpCache() response 'dump' field not an array");
+
+        if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
+                JsonVariant *i;
+
+                JSON_VARIANT_ARRAY_FOREACH(i, d) {
+                        r = dump_cache_scope(i);
+                        if (r < 0)
+                                return r;
+                }
+
+                return 0;
+        }
+
+        return json_variant_dump(d, arg_json_format_flags, NULL, NULL);
+}
+
 static void help_protocol_types(void) {
         if (arg_legend)
                 puts("Known protocol types:");
@@ -2913,6 +3036,7 @@ static int native_help(void) {
                "  flush-caches                 Flush all local DNS caches\n"
                "  reset-server-features        Forget learnt DNS server feature levels\n"
                "  monitor                      Monitor DNS queries\n"
+               "  show-cache                   Show cache contents\n"
                "  dns [LINK [SERVER...]]       Get/set per-interface DNS server address\n"
                "  domain [LINK [DOMAIN...]]    Get/set per-interface search domain\n"
                "  default-route [LINK [BOOL]]  Get/set per-interface default route flag\n"
@@ -3559,6 +3683,7 @@ static int native_main(int argc, char *argv[], sd_bus *bus) {
                 { "revert",                VERB_ANY, 2,        0,            verb_revert_link      },
                 { "log-level",             VERB_ANY, 2,        0,            verb_log_level        },
                 { "monitor",               VERB_ANY, 1,        0,            verb_monitor          },
+                { "show-cache",            VERB_ANY, 1,        0,            verb_show_cache       },
                 {}
         };
 
index 12d0d28babb9a896c0cc6b18fc771f22833a4e63..334ae8dcff5a31b66f376ebfae33168cc55beee6 100644 (file)
@@ -1677,34 +1677,6 @@ static int bus_property_get_dnssec_statistics(
                                      (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]);
 }
 
-static int bus_property_get_ntas(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        Manager *m = ASSERT_PTR(userdata);
-        const char *domain;
-        int r;
-
-        assert(reply);
-
-        r = sd_bus_message_open_container(reply, 'a', "s");
-        if (r < 0)
-                return r;
-
-        SET_FOREACH(domain, m->trust_anchor.negative_by_name) {
-                r = sd_bus_message_append(reply, "s", domain);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_message_close_container(reply);
-}
-
 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode);
 static BUS_DEFINE_PROPERTY_GET(bus_property_get_dnssec_supported, "b", Manager, manager_dnssec_supported);
 static BUS_DEFINE_PROPERTY_GET2(bus_property_get_dnssec_mode, "s", Manager, manager_get_dnssec_mode, dnssec_mode_to_string);
@@ -2102,7 +2074,7 @@ static const sd_bus_vtable resolve_vtable[] = {
         SD_BUS_PROPERTY("DNSSEC", "s", bus_property_get_dnssec_mode, 0, 0),
         SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
         SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 0, 0),
-        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
+        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_string_set, offsetof(Manager, trust_anchor.negative_by_name), 0),
         SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
         SD_BUS_PROPERTY("ResolvConfMode", "s", bus_property_get_resolv_conf_mode, 0, 0),
 
index 2f97cf7730db71434e945ed05c03d1404aaebaff..089ed3aa0a97180b873a0b2b4e01bd995e10ef2d 100644 (file)
@@ -1351,6 +1351,86 @@ void dns_cache_dump(DnsCache *cache, FILE *f) {
                 }
 }
 
+int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret) {
+        _cleanup_(json_variant_unrefp) JsonVariant *c = NULL;
+        DnsCacheItem *i;
+        int r;
+
+        assert(cache);
+        assert(ret);
+
+        HASHMAP_FOREACH(i, cache->by_key) {
+                _cleanup_(json_variant_unrefp) JsonVariant *d = NULL, *k = NULL;
+
+                r = dns_resource_key_to_json(i->key, &k);
+                if (r < 0)
+                        return r;
+
+                if (i->rr) {
+                        _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
+
+                        LIST_FOREACH(by_key, j, i) {
+                                _cleanup_(json_variant_unrefp) JsonVariant *rj = NULL, *item = NULL;
+
+                                assert(j->rr);
+
+                                r = dns_resource_record_to_json(j->rr, &rj);
+                                if (r < 0)
+                                        return r;
+
+                                r = dns_resource_record_to_wire_format(j->rr, /* canonical= */ false); /* don't use DNSSEC canonical format, since it removes casing, but we want that for DNS_SD compat */
+                                if (r < 0)
+                                        return r;
+
+                                r = json_build(&item, JSON_BUILD_OBJECT(
+                                                               JSON_BUILD_PAIR_VARIANT("rr", rj),
+                                                               JSON_BUILD_PAIR_BASE64("raw", j->rr->wire_format, j->rr->wire_format_size)));
+                                if (r < 0)
+                                        return r;
+
+                                r = json_variant_append_array(&l, item);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        if (!l) {
+                                r = json_variant_new_array(&l, NULL, 0);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        r = json_build(&d,
+                                       JSON_BUILD_OBJECT(
+                                                       JSON_BUILD_PAIR_VARIANT("key", k),
+                                                       JSON_BUILD_PAIR_VARIANT("rrs", l),
+                                                       JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
+                } else if (i->type == DNS_CACHE_NODATA) {
+                        r = json_build(&d,
+                                       JSON_BUILD_OBJECT(
+                                                       JSON_BUILD_PAIR_VARIANT("key", k),
+                                                       JSON_BUILD_PAIR_EMPTY_ARRAY("rrs"),
+                                                       JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
+                } else
+                        r = json_build(&d,
+                                       JSON_BUILD_OBJECT(
+                                                       JSON_BUILD_PAIR_VARIANT("key", k),
+                                                       JSON_BUILD_PAIR_STRING("type", dns_cache_item_type_to_string(i)),
+                                                       JSON_BUILD_PAIR_UNSIGNED("until", i->until)));
+                if (r < 0)
+                        return r;
+
+                r = json_variant_append_array(&c, d);
+                if (r < 0)
+                        return r;
+        }
+
+        if (!c)
+                return json_variant_new_array(ret, NULL, 0);
+
+        *ret = TAKE_PTR(c);
+        return 0;
+}
+
 bool dns_cache_is_empty(DnsCache *cache) {
         if (!cache)
                 return true;
index 42e744a9108477921698b6ed4c657373f83d0644..bc045bc80c8a165a4c07ab295d295c6a2fbb44ae 100644 (file)
@@ -50,6 +50,8 @@ int dns_cache_lookup(
 int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address);
 
 void dns_cache_dump(DnsCache *cache, FILE *f);
+int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret);
+
 bool dns_cache_is_empty(DnsCache *cache);
 
 unsigned dns_cache_size(DnsCache *cache);
index 574a1a4be92bb62144bdc380d1b5e46ff83cf5b6..d63760b7d1e2353db3e0063ba1beade35b1ba500 100644 (file)
@@ -911,9 +911,9 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAns
                 if (r < 0)
                         goto fail;
 
-                /* RFC 2782 states "Unless and until permitted by future standards
-                 * action, name compression is not to be used for this field." */
-                r = dns_packet_append_name(p, rr->srv.name, false, true, NULL);
+                /* RFC 2782 states "Unless and until permitted by future standards action, name compression
+                 * is not to be used for this field." Hence we turn off compression here. */
+                r = dns_packet_append_name(p, rr->srv.name, /* allow_compression= */ false, /* canonical_candidate= */ true, NULL);
                 break;
 
         case DNS_TYPE_PTR:
@@ -1728,7 +1728,13 @@ int dns_packet_read_rr(
                 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
                 if (r < 0)
                         return r;
-                r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
+
+                /* RFC 2782 states "Unless and until permitted by future standards action, name compression
+                 * is not to be used for this field." Nonetheless, we support it here, in the interest of
+                 * increasing compatibility with implementations that do not implement this correctly. After
+                 * all we didn't do this right once upon a time ourselves (see
+                 * https://github.com/systemd/systemd/issues/9793). */
+                r = dns_packet_read_name(p, &rr->srv.name, /* allow_compression= */ true, NULL);
                 break;
 
         case DNS_TYPE_PTR:
index 603bb1a10d5ea8dde87d11f529eeed22f27054f4..f6344542d6e8631f7ddf5b89801a0d5503364278 100644 (file)
@@ -1853,6 +1853,34 @@ int dns_resource_key_to_json(DnsResourceKey *key, JsonVariant **ret) {
                                           JSON_BUILD_PAIR("name", JSON_BUILD_STRING(dns_resource_key_name(key)))));
 }
 
+int dns_resource_key_from_json(JsonVariant *v, DnsResourceKey **ret) {
+        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
+        uint16_t type = 0, class = 0;
+        const char *name = NULL;
+        int r;
+
+        JsonDispatch dispatch_table[] = {
+                { "class", JSON_VARIANT_INTEGER, json_dispatch_uint16,       PTR_TO_SIZE(&class), JSON_MANDATORY },
+                { "type",  JSON_VARIANT_INTEGER, json_dispatch_uint16,       PTR_TO_SIZE(&type),  JSON_MANDATORY },
+                { "name",  JSON_VARIANT_STRING,  json_dispatch_const_string, PTR_TO_SIZE(&name),  JSON_MANDATORY },
+                {}
+        };
+
+        assert(v);
+        assert(ret);
+
+        r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
+        if (r < 0)
+                return r;
+
+        key = dns_resource_key_new(class, type, name);
+        if (!key)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(key);
+        return 0;
+}
+
 static int type_bitmap_to_json(Bitmap *b, JsonVariant **ret) {
         _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
         unsigned t;
index 024cfb874470f364fad13568307462b803e88fb8..fd15cc343d859ef3b632c4d2bb362532746e59b3 100644 (file)
@@ -317,6 +317,9 @@ int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *
 char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size);
 ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out);
 
+#define DNS_RESOURCE_KEY_TO_STRING(key) \
+        dns_resource_key_to_string(key, (char[DNS_RESOURCE_KEY_STRING_MAX]) {}, DNS_RESOURCE_KEY_STRING_MAX)
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref);
 
 static inline bool dns_key_is_shared(const DnsResourceKey *key) {
@@ -368,6 +371,7 @@ int dns_txt_item_new_empty(DnsTxtItem **ret);
 int dns_resource_record_new_from_raw(DnsResourceRecord **ret, const void *data, size_t size);
 
 int dns_resource_key_to_json(DnsResourceKey *key, JsonVariant **ret);
+int dns_resource_key_from_json(JsonVariant *v, DnsResourceKey **ret);
 int dns_resource_record_to_json(DnsResourceRecord *rr, JsonVariant **ret);
 
 void dns_resource_record_hash_func(const DnsResourceRecord *i, struct siphash *state);
index 45f1d3631196564bc5d61674e3dca19400b10d77..35085a6ef57deb94e4a9266da3697e463d21ee08 100644 (file)
@@ -1643,3 +1643,23 @@ bool dns_scope_is_default_route(DnsScope *scope) {
          * volunteer as default route. */
         return !dns_scope_has_route_only_domains(scope);
 }
+
+int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret) {
+        _cleanup_(json_variant_unrefp) JsonVariant *cache = NULL;
+        int r;
+
+        assert(scope);
+        assert(ret);
+
+        r = dns_cache_dump_to_json(&scope->cache, &cache);
+        if (r < 0)
+                return r;
+
+        return json_build(ret,
+                          JSON_BUILD_OBJECT(
+                                          JSON_BUILD_PAIR_STRING("protocol", dns_protocol_to_string(scope->protocol)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->family != AF_UNSPEC, "family", JSON_BUILD_INTEGER(scope->family)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->link, "ifindex", JSON_BUILD_INTEGER(scope->link ? scope->link->ifindex : 0)),
+                                          JSON_BUILD_PAIR_CONDITION(scope->link, "ifname", JSON_BUILD_STRING(scope->link ? scope->link->ifname : NULL)),
+                                          JSON_BUILD_PAIR_VARIANT("cache", cache)));
+}
index 1f9d22b7d18a0b721330aa1e5a9c33b08ac6c8d6..ca33fd007a6aeaf077d0364061242e6336440910 100644 (file)
@@ -110,3 +110,5 @@ int dns_scope_add_dnssd_services(DnsScope *scope);
 int dns_scope_remove_dnssd_services(DnsScope *scope);
 
 bool dns_scope_is_default_route(DnsScope *scope);
+
+int dns_scope_dump_cache_to_json(DnsScope *scope, JsonVariant **ret);
index 3a7d6977f67fac24926231d7bb77ec2df545f54f..259f82eff4e81d8610d28061837b5a202a4c3e34 100644 (file)
@@ -1205,7 +1205,7 @@ static int manager_dns_stub_fd(
                 return -errno;
 
         if (type == SOCK_STREAM &&
-            listen(fd, SOMAXCONN) < 0)
+            listen(fd, SOMAXCONN_DELUXE) < 0)
                 return -errno;
 
         r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
@@ -1295,7 +1295,7 @@ static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int ty
                 goto fail;
 
         if (type == SOCK_STREAM &&
-            listen(fd, SOMAXCONN) < 0) {
+            listen(fd, SOMAXCONN_DELUXE) < 0) {
                 r = -errno;
                 goto fail;
         }
index 9b6d14f20cc92d197566d48cfcfa386e62fedb00..4f8f591306cbefeceba4bd1851030a7786d3a443 100644 (file)
@@ -207,34 +207,6 @@ static int property_get_scopes_mask(
         return sd_bus_message_append(reply, "t", mask);
 }
 
-static int property_get_ntas(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        Link *l = ASSERT_PTR(userdata);
-        const char *name;
-        int r;
-
-        assert(reply);
-
-        r = sd_bus_message_open_container(reply, 'a', "s");
-        if (r < 0)
-                return r;
-
-        SET_FOREACH(name, l->dnssec_negative_trust_anchors) {
-                r = sd_bus_message_append(reply, "s", name);
-                if (r < 0)
-                        return r;
-        }
-
-        return sd_bus_message_close_container(reply);
-}
-
 static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
         assert(l);
 
@@ -870,7 +842,7 @@ static const sd_bus_vtable link_vtable[] = {
         SD_BUS_PROPERTY("MulticastDNS", "s", property_get_mdns_support, 0, 0),
         SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
         SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
-        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
+        SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_string_set, offsetof(Link, dnssec_negative_trust_anchors), 0),
         SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
 
         SD_BUS_METHOD_WITH_ARGS("SetDNS",
index 4ab455eb2fe45e4080c240913c9e423ebb3dae6b..8fac351ee6da033f97041a2cadc27227f83c6bff 100644 (file)
@@ -392,7 +392,7 @@ int manager_llmnr_ipv4_tcp_fd(Manager *m) {
                         return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set SO_REUSEADDR: %m");
         }
 
-        r = listen(s, SOMAXCONN);
+        r = listen(s, SOMAXCONN_DELUXE);
         if (r < 0)
                 return log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to listen the stream: %m");
 
@@ -457,7 +457,7 @@ int manager_llmnr_ipv6_tcp_fd(Manager *m) {
                         return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set SO_REUSEADDR: %m");
         }
 
-        r = listen(s, SOMAXCONN);
+        r = listen(s, SOMAXCONN_DELUXE);
         if (r < 0)
                 return log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to listen the stream: %m");
 
index f878d9ee3fe57e804084a547f01b5614e7c2ed9f..fc224f627e8f71a56c4ba7ea492e78e29c7cdd55 100644 (file)
@@ -563,6 +563,40 @@ static int vl_method_subscribe_dns_resolves(Varlink *link, JsonVariant *paramete
         return 1;
 }
 
+static int vl_method_dump_cache(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
+        _cleanup_(json_variant_unrefp) JsonVariant *list = NULL;
+        Manager *m;
+        int r;
+
+        assert(link);
+
+        if (json_variant_elements(parameters) > 0)
+                return varlink_error_invalid_parameter(link, parameters);
+
+        m = ASSERT_PTR(varlink_server_get_userdata(varlink_get_server(link)));
+
+        LIST_FOREACH(scopes, s, m->dns_scopes) {
+                _cleanup_(json_variant_unrefp) JsonVariant *j = NULL;
+
+                r = dns_scope_dump_cache_to_json(s, &j);
+                if (r < 0)
+                        return r;
+
+                r = json_variant_append_array(&list, j);
+                if (r < 0)
+                        return r;
+        }
+
+        if (!list) {
+                r = json_variant_new_array(&list, NULL, 0);
+                if (r < 0)
+                        return r;
+        }
+
+        return varlink_replyb(link, JSON_BUILD_OBJECT(
+                                              JSON_BUILD_PAIR("dump", JSON_BUILD_VARIANT(list))));
+}
+
 static int varlink_monitor_server_init(Manager *m) {
         _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
         int r;
@@ -578,10 +612,10 @@ static int varlink_monitor_server_init(Manager *m) {
 
         varlink_server_set_userdata(server, m);
 
-        r = varlink_server_bind_method(
+        r = varlink_server_bind_method_many(
                         server,
-                        "io.systemd.Resolve.Monitor.SubscribeQueryResults",
-                        vl_method_subscribe_dns_resolves);
+                        "io.systemd.Resolve.Monitor.SubscribeQueryResults", vl_method_subscribe_dns_resolves,
+                        "io.systemd.Resolve.Monitor.DumpCache", vl_method_dump_cache);
         if (r < 0)
                 return log_error_errno(r, "Failed to register varlink methods: %m");
 
index 948a5e3b9d6a4216f8a63ed1c0647a6e8b97c82b..43d72f9db751303b928109d80d5a8fa5d35ff4e4 100644 (file)
@@ -267,13 +267,11 @@ int battery_is_discharging_and_low(void) {
         }
 
         /* If we found a battery whose state we couldn't read, don't assume we are in low battery state */
-        if (unsure)
+        if (unsure) {
+                log_debug("Found battery with unreadable state, assuming not in low battery state.");
                 return false;
+        }
 
-        /* Found no charged battery, but did find low batteries */
-        if (found_low)
-                return true;
-
-        /* Found neither charged nor low batteries? let's return that we aren't on low battery state */
-        return false;
+        /* If found neither charged nor low batteries, assume that we aren't in low battery state */
+        return found_low;
 }
index 16295a582377cc7db3aeb21a7f5abbe6464f6eea..f86645e4eed91859a1afe2857c84984d4cdbef88 100644 (file)
@@ -17,6 +17,7 @@
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "btrfs-util.h"
+#include "chase.h"
 #include "chattr-util.h"
 #include "copy.h"
 #include "fd-util.h"
@@ -70,32 +71,20 @@ static int extract_subvolume_name(const char *path, char **ret) {
         return 0;
 }
 
-int btrfs_is_subvol_fd(int fd) {
+int btrfs_is_subvol_at(int dir_fd, const char *path) {
         struct stat st;
 
-        assert(fd >= 0);
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
 
         /* On btrfs subvolumes always have the inode 256 */
 
-        if (fstat(fd, &st) < 0)
+        if (fstatat(dir_fd, strempty(path), &st, isempty(path) ? AT_EMPTY_PATH : 0) < 0)
                 return -errno;
 
         if (!btrfs_might_be_subvol(&st))
                 return 0;
 
-        return fd_is_fs_type(fd, BTRFS_SUPER_MAGIC);
-}
-
-int btrfs_is_subvol(const char *path) {
-        _cleanup_close_ int fd = -EBADF;
-
-        assert(path);
-
-        fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-        if (fd < 0)
-                return -errno;
-
-        return btrfs_is_subvol_fd(fd);
+        return is_fs_type_at(dir_fd, path, BTRFS_SUPER_MAGIC);
 }
 
 int btrfs_subvol_make_fd(int fd, const char *subvolume) {
@@ -163,11 +152,16 @@ int btrfs_subvol_make_fallback(const char *path, mode_t mode) {
         return 0; /* plain directory */
 }
 
-int btrfs_subvol_set_read_only_fd(int fd, bool b) {
+int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b) {
+        _cleanup_close_ int fd = -EBADF;
         uint64_t flags, nflags;
         struct stat st;
 
-        assert(fd >= 0);
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
+        fd = xopenat(dir_fd, path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0);
+        if (fd < 0)
+                return fd;
 
         if (fstat(fd, &st) < 0)
                 return -errno;
@@ -185,16 +179,6 @@ int btrfs_subvol_set_read_only_fd(int fd, bool b) {
         return RET_NERRNO(ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &nflags));
 }
 
-int btrfs_subvol_set_read_only(const char *path, bool b) {
-        _cleanup_close_ int fd = -EBADF;
-
-        fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-        if (fd < 0)
-                return -errno;
-
-        return btrfs_subvol_set_read_only_fd(fd, b);
-}
-
 int btrfs_subvol_get_read_only_fd(int fd) {
         uint64_t flags;
         struct stat st;
@@ -1135,25 +1119,21 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
         return 0;
 }
 
-int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
+int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags) {
         _cleanup_free_ char *subvolume = NULL;
         _cleanup_close_ int fd = -EBADF;
         int r;
 
         assert(path);
 
-        r = extract_subvolume_name(path, &subvolume);
-        if (r < 0)
-                return r;
-
-        fd = open_parent(path, O_CLOEXEC, 0);
+        fd = chase_and_openat(dir_fd, path, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume);
         if (fd < 0)
                 return fd;
 
-        return subvol_remove_children(fd, subvolume, 0, flags);
-}
+        r = validate_subvolume_name(subvolume);
+        if (r < 0)
+                return r;
 
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
         return subvol_remove_children(fd, subvolume, 0, flags);
 }
 
@@ -1526,22 +1506,37 @@ static int subvol_snapshot_children(
         return 0;
 }
 
-int btrfs_subvol_snapshot_fd_full(
-                int old_fd,
-                const char *new_path,
+int btrfs_subvol_snapshot_at_full(
+                int dir_fdf,
+                const char *from,
+                int dir_fdt,
+                const char *to,
                 BtrfsSnapshotFlags flags,
                 copy_progress_path_t progress_path,
                 copy_progress_bytes_t progress_bytes,
                 void *userdata) {
 
         _cleanup_free_ char *subvolume = NULL;
-        _cleanup_close_ int new_fd = -EBADF;
+        _cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
         int r;
 
-        assert(old_fd >= 0);
-        assert(new_path);
+        assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
+        assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD);
+        assert(to);
+
+        old_fd = xopenat(dir_fdf, from, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0);
+        if (old_fd < 0)
+                return old_fd;
 
-        r = btrfs_is_subvol_fd(old_fd);
+        new_fd = chase_and_openat(dir_fdt, to, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume);
+        if (new_fd < 0)
+                return new_fd;
+
+        r = validate_subvolume_name(subvolume);
+        if (r < 0)
+                return r;
+
+        r = btrfs_is_subvol_at(dir_fdf, from);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -1551,18 +1546,19 @@ int btrfs_subvol_snapshot_fd_full(
                 if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
                         return -EISDIR;
 
-                r = btrfs_subvol_make(new_path);
+                r = btrfs_subvol_make_fd(new_fd, subvolume);
                 if (ERRNO_IS_NOT_SUPPORTED(r) && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
                         /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
-                        if (mkdir(new_path, 0755) < 0)
+                        if (mkdirat(new_fd, subvolume, 0755) < 0)
                                 return -errno;
 
                         plain_directory = true;
                 } else if (r < 0)
                         return r;
 
-                r = copy_directory_fd_full(
-                                old_fd, new_path,
+                r = copy_directory_at_full(
+                                dir_fdf, from,
+                                new_fd, subvolume,
                                 COPY_MERGE_EMPTY|
                                 COPY_REFLINK|
                                 COPY_SAME_MOUNT|
@@ -1583,9 +1579,9 @@ int btrfs_subvol_snapshot_fd_full(
                                  * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
 
                                 if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE)
-                                        (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
+                                        (void) chattr_at(new_fd, subvolume, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL);
                         } else {
-                                r = btrfs_subvol_set_read_only(new_path, true);
+                                r = btrfs_subvol_set_read_only_at(new_fd, subvolume, true);
                                 if (r < 0)
                                         goto fallback_fail;
                         }
@@ -1594,41 +1590,13 @@ int btrfs_subvol_snapshot_fd_full(
                 return 0;
 
         fallback_fail:
-                (void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+                (void) rm_rf_at(new_fd, subvolume, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
                 return r;
         }
 
-        r = extract_subvolume_name(new_path, &subvolume);
-        if (r < 0)
-                return r;
-
-        new_fd = open_parent(new_path, O_CLOEXEC, 0);
-        if (new_fd < 0)
-                return new_fd;
-
         return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
 }
 
-int btrfs_subvol_snapshot_full(
-                const char *old_path,
-                const char *new_path,
-                BtrfsSnapshotFlags flags,
-                copy_progress_path_t progress_path,
-                copy_progress_bytes_t progress_bytes,
-                void *userdata) {
-
-        _cleanup_close_ int old_fd = -EBADF;
-
-        assert(old_path);
-        assert(new_path);
-
-        old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-        if (old_fd < 0)
-                return -errno;
-
-        return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, progress_path, progress_bytes, userdata);
-}
-
 int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
 
         struct btrfs_ioctl_search_args args = {
index 0ce6d4b96ada717bb8ea1bd57b933c439300efc4..de38f1e45c39a8578f5e6e99c2399712ad10c083 100644 (file)
@@ -43,8 +43,13 @@ typedef enum BtrfsRemoveFlags {
         BTRFS_REMOVE_QUOTA     = 1 << 1,
 } BtrfsRemoveFlags;
 
-int btrfs_is_subvol_fd(int fd);
-int btrfs_is_subvol(const char *path);
+int btrfs_is_subvol_at(int dir_fd, const char *path);
+static inline int btrfs_is_subvol_fd(int fd) {
+        return btrfs_is_subvol_at(fd, NULL);
+}
+static inline int btrfs_is_subvol(const char *path) {
+        return btrfs_is_subvol_at(AT_FDCWD, path);
+}
 
 int btrfs_get_block_device_at(int dir_fd, const char *path, dev_t *ret);
 static inline int btrfs_get_block_device(const char *path, dev_t *ret) {
@@ -69,21 +74,24 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume);
 
 int btrfs_subvol_make_fallback(const char *path, mode_t);
 
-int btrfs_subvol_snapshot_fd_full(int old_fd, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
-static inline int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
-        return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, NULL, NULL, NULL);
+int btrfs_subvol_snapshot_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int btrfs_subvol_snapshot_at(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags) {
+        return btrfs_subvol_snapshot_at_full(dir_fdf, from, dir_fdt, to, flags, NULL, NULL, NULL);
 }
 
-int btrfs_subvol_snapshot_full(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
-static inline int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
-        return btrfs_subvol_snapshot_full(old_path, new_path, flags, NULL, NULL, NULL);
+int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags);
+static inline int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
+        return btrfs_subvol_remove_at(AT_FDCWD, path, flags);
 }
 
-int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
+int btrfs_subvol_set_read_only_at(int dir_fd, const char *path, bool b);
+static inline int btrfs_subvol_set_read_only_fd(int fd, bool b) {
+        return btrfs_subvol_set_read_only_at(fd, NULL, b);
+}
+static inline int btrfs_subvol_set_read_only(const char *path, bool b) {
+        return btrfs_subvol_set_read_only_at(AT_FDCWD, path, b);
+}
 
-int btrfs_subvol_set_read_only_fd(int fd, bool b);
-int btrfs_subvol_set_read_only(const char *path, bool b);
 int btrfs_subvol_get_read_only_fd(int fd);
 
 int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
index 8b1a353a9b3df512542191e5b7b230d51c3b8f18..6e93d0ca434bfb9441bbc9f33273cbb6555b81b3 100644 (file)
@@ -1209,6 +1209,17 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                 return 1;
         }
 
+        if (streq(field, "ImportCredential")) {
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
+                else
+                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                return 1;
+        }
+
         if (streq(field, "LogExtraFields")) {
                 r = sd_bus_message_open_container(m, 'r', "sv");
                 if (r < 0)
index 4eb1b1c316194bda1daa3e715f9687da3c304d17..d4c91fa3aab36ca538dee85d31192d53bea17a97 100644 (file)
@@ -678,3 +678,40 @@ const struct hash_ops bus_message_hash_ops = {
         .compare = trivial_compare_func,
         .free_value = bus_message_unref_wrapper,
 };
+
+int bus_message_append_string_set(sd_bus_message *m, Set *set) {
+        const char *s;
+        int r;
+
+        assert(m);
+
+        r = sd_bus_message_open_container(m, 'a', "s");
+        if (r < 0)
+                return r;
+
+        SET_FOREACH(s, set) {
+                r = sd_bus_message_append(m, "s", s);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(m);
+}
+
+int bus_property_get_string_set(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Set **s = ASSERT_PTR(userdata);
+
+        assert(bus);
+        assert(property);
+        assert(reply);
+
+        return bus_message_append_string_set(reply, *s);
+}
index 81f5d0f15221a97696e76f96f1dad70401dcd4fd..869c639aeb44e7cacbb2a7627ed62c14b36e5052 100644 (file)
@@ -12,6 +12,7 @@
 #include "errno-util.h"
 #include "macro.h"
 #include "runtime-scope.h"
+#include "set.h"
 #include "string-util.h"
 #include "time-util.h"
 
@@ -68,3 +69,7 @@ int bus_reply_pair_array(sd_bus_message *m, char **l);
 int bus_register_malloc_status(sd_bus *bus, const char *destination);
 
 extern const struct hash_ops bus_message_hash_ops;
+
+int bus_message_append_string_set(sd_bus_message *m, Set *s);
+
+int bus_property_get_string_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
index f17d97a2c101226ed3d956d69f4894127e33d070..2665930209776325009e9cdb32aef15ff378f69e 100644 (file)
@@ -649,7 +649,7 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
                 if (repeat == 0)
                         return -ERANGE;
         } else {
-                /* If no repeat value is specified for the µs component, then let's explicitly refuse ranges
+                /* If no repeat value is specified for the μs component, then let's explicitly refuse ranges
                  * below 1s because our default repeat granularity is beyond that. */
 
                 /* Overflow check */
index 14b9b61d8a24e961e00635a42733ea6869061444..9c2217856182f47d937799a4edc5f900a396ee85 100644 (file)
@@ -245,7 +245,7 @@ int copy_bytes_full(
                 ssize_t n;
 
                 if (max_bytes <= 0)
-                        return 1; /* return > 0 if we hit the max_bytes limit */
+                        break;
 
                 r = look_for_signals(copy_flags);
                 if (r < 0)
@@ -468,7 +468,16 @@ int copy_bytes_full(
                 copied_something = true;
         }
 
-        return 0; /* return 0 if we hit EOF earlier than the size limit */
+        if (copy_flags & COPY_TRUNCATE) {
+                off_t off = lseek(fdt, 0, SEEK_CUR);
+                if (off < 0)
+                        return -errno;
+
+                if (ftruncate(fdt, off) < 0)
+                        return -errno;
+        }
+
+        return max_bytes <= 0; /* return 0 if we hit EOF earlier than the size limit */
 }
 
 static int fd_copy_symlink(
@@ -1208,61 +1217,22 @@ int copy_tree_at_full(
         return 0;
 }
 
-static int sync_dir_by_flags(const char *path, CopyFlags copy_flags) {
+static int sync_dir_by_flags(int dir_fd, const char *path, CopyFlags copy_flags) {
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(path);
 
         if (copy_flags & COPY_SYNCFS)
-                return syncfs_path(AT_FDCWD, path);
+                return syncfs_path(dir_fd, path);
         if (copy_flags & COPY_FSYNC_FULL)
-                return fsync_parent_at(AT_FDCWD, path);
-
-        return 0;
-}
-
-int copy_directory_fd_full(
-                int dirfd,
-                const char *to,
-                CopyFlags copy_flags,
-                copy_progress_path_t progress_path,
-                copy_progress_bytes_t progress_bytes,
-                void *userdata) {
-
-        struct stat st;
-        int r;
-
-        assert(dirfd >= 0);
-        assert(to);
-
-        if (fstat(dirfd, &st) < 0)
-                return -errno;
-
-        r = stat_verify_directory(&st);
-        if (r < 0)
-                return r;
-
-        r = fd_copy_directory(
-                        dirfd, NULL,
-                        &st,
-                        AT_FDCWD, to,
-                        st.st_dev,
-                        COPY_DEPTH_MAX,
-                        UID_INVALID, GID_INVALID,
-                        copy_flags,
-                        NULL, NULL, NULL,
-                        progress_path,
-                        progress_bytes,
-                        userdata);
-        if (r < 0)
-                return r;
-
-        r = sync_dir_by_flags(to, copy_flags);
-        if (r < 0)
-                return r;
+                return fsync_parent_at(dir_fd, path);
 
         return 0;
 }
 
-int copy_directory_full(
+int copy_directory_at_full(
+                int dir_fdf,
                 const char *from,
+                int dir_fdt,
                 const char *to,
                 CopyFlags copy_flags,
                 copy_progress_path_t progress_path,
@@ -1272,10 +1242,11 @@ int copy_directory_full(
         struct stat st;
         int r;
 
-        assert(from);
+        assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD);
+        assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD);
         assert(to);
 
-        if (lstat(from, &st) < 0)
+        if (fstatat(dir_fdf, strempty(from), &st, AT_SYMLINK_NOFOLLOW|(isempty(from) ? AT_EMPTY_PATH : 0)) < 0)
                 return -errno;
 
         r = stat_verify_directory(&st);
@@ -1283,9 +1254,9 @@ int copy_directory_full(
                 return r;
 
         r = fd_copy_directory(
-                        AT_FDCWD, from,
+                        dir_fdf, from,
                         &st,
-                        AT_FDCWD, to,
+                        dir_fdt, to,
                         st.st_dev,
                         COPY_DEPTH_MAX,
                         UID_INVALID, GID_INVALID,
@@ -1297,7 +1268,7 @@ int copy_directory_full(
         if (r < 0)
                 return r;
 
-        r = sync_dir_by_flags(to, copy_flags);
+        r = sync_dir_by_flags(dir_fdt, to, copy_flags);
         if (r < 0)
                 return r;
 
@@ -1494,7 +1465,7 @@ int copy_file_atomic_at_full(
                         return -errno;
         }
 
-        r = link_tmpfile_at(fdt, dir_fdt, t, to, copy_flags & COPY_REPLACE);
+        r = link_tmpfile_at(fdt, dir_fdt, t, to, (copy_flags & COPY_REPLACE) ? LINK_TMPFILE_REPLACE : 0);
         if (r < 0)
                 return r;
 
index c4482eba7e1faf3f21e2cc32c6e4de07a383de96..da084b66f299e8925499a928c6bf31300c8960a1 100644 (file)
@@ -28,6 +28,7 @@ typedef enum CopyFlags {
         COPY_ALL_XATTRS    = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */
         COPY_HOLES         = 1 << 14, /* Copy holes */
         COPY_GRACEFUL_WARN = 1 << 15, /* Skip copying file types that aren't supported by the target filesystem */
+        COPY_TRUNCATE      = 1 << 16, /* Truncate to current file offset after copying */
 } CopyFlags;
 
 typedef enum DenyType {
@@ -82,14 +83,9 @@ static inline int copy_tree(const char *from, const char *to, uid_t override_uid
         return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
 }
 
-int copy_directory_fd_full(int dirfd, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
-static inline int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
-        return copy_directory_fd_full(dirfd, to, copy_flags, NULL, NULL, NULL);
-}
-
-int copy_directory_full(const char *from, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
-static inline int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
-        return copy_directory_full(from, to, copy_flags, NULL, NULL, NULL);
+int copy_directory_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int copy_directory_at(int dir_fdf, const char *from, int dir_fdt, const char *to, CopyFlags copy_flags) {
+        return copy_directory_at_full(dir_fdf, from, dir_fdt, to, copy_flags, NULL, NULL, NULL);
 }
 
 int copy_bytes_full(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, size_t *ret_remains_size, copy_progress_bytes_t progress, void *userdata);
index 198c975c443c85320c11e5ee7334da9f0fde1c06..d93a1cc74c2cfec74175cb31bc58edeee8738122 100644 (file)
@@ -923,13 +923,13 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
 
                 new_path = strjoina("/var/lib/machines/", new_name);
 
-                r = btrfs_subvol_snapshot(i->path, new_path,
-                                          (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
-                                          BTRFS_SNAPSHOT_FALLBACK_COPY |
-                                          BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
-                                          BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
-                                          BTRFS_SNAPSHOT_RECURSIVE |
-                                          BTRFS_SNAPSHOT_QUOTA);
+                r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, new_path,
+                                             (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+                                             BTRFS_SNAPSHOT_FALLBACK_COPY |
+                                             BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+                                             BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+                                             BTRFS_SNAPSHOT_RECURSIVE |
+                                             BTRFS_SNAPSHOT_QUOTA);
                 if (r >= 0)
                         /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
                         (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
index f77f8351cf95dff4f1f5307ce3a7f5b7eee45ca1..e3ec91b8771e2ed57979d97dcaa12f4e2dfc1441 100644 (file)
@@ -309,7 +309,7 @@ int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
                 return -ERANGE;
 
         cache_stat = new_stat;
-        *ret = cache = sec * USEC_PER_SEC; /* return in µs */
+        *ret = cache = sec * USEC_PER_SEC; /* return in μs */
         return 0;
 }
 
diff --git a/src/shared/ethtool-link-mode.py b/src/shared/ethtool-link-mode.py
new file mode 100644 (file)
index 0000000..aac1576
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+import re
+import shlex
+import subprocess
+import sys
+
+OVERRIDES = {
+    'autoneg' : 'autonegotiation',
+}
+
+mode, cpp, header = sys.argv[1:]
+xml = mode == '--xml'
+
+command = [*shlex.split(cpp), '-include', header, '-']
+out = subprocess.check_output(command, stdin=subprocess.DEVNULL, universal_newlines=True)
+
+lines = iter(out.splitlines())
+for line in lines:
+    if line.startswith('enum ethtool_link_mode_bit_indices {'):
+        break
+
+entries = []
+for line in lines:
+    if line.startswith('}'):
+        break
+    # ETHTOOL_LINK_MODE_10baseT_Half_BIT       = 0,
+    m = re.match(r'^\s*(ETHTOOL_LINK_MODE_((\d*).*)_BIT)\s*=\s*(\d+),', line)
+    if not m:
+        continue
+    enum, name, speed, value = m.groups()
+
+    name = name.lower().replace('_', '-')
+    name = OVERRIDES.get(name, name)
+
+    duplex = name.split('-')[-1].lower()
+    if duplex not in {'half', 'full'}:
+        duplex = ''
+
+    entries += [(enum, name, speed, value, duplex)]
+
+if xml:
+    print('              <tbody>')
+
+    entries.sort(key=lambda entry: (int(entry[2]) if entry[2] else 1e20, entry[4], entry[1], entry[3]))
+
+for enum, name, speed, value, duplex in entries:
+    if xml:
+        print(f'''\
+                <row><entry><option>{name}</option></entry>
+                <entry>{speed}</entry><entry>{duplex}</entry></row>
+        ''')
+    else:
+        enum = f'[{enum}]'
+        print(f'        {enum:50} = "{name}",')
+
+if xml:
+    print('              </tbody>')
+
+assert len(entries) >= 99
index e978b8bf7ea34871e04c083ef2f833047bcfc9d7..dce9e005fee495924740772e2b7f1d19c0b70d49 100644 (file)
@@ -151,98 +151,7 @@ static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
 };
 
 static const char* const ethtool_link_mode_bit_table[] = {
-        [ETHTOOL_LINK_MODE_10baseT_Half_BIT]               = "10baset-half",
-        [ETHTOOL_LINK_MODE_10baseT_Full_BIT]               = "10baset-full",
-        [ETHTOOL_LINK_MODE_100baseT_Half_BIT]              = "100baset-half",
-        [ETHTOOL_LINK_MODE_100baseT_Full_BIT]              = "100baset-full",
-        [ETHTOOL_LINK_MODE_1000baseT_Half_BIT]             = "1000baset-half",
-        [ETHTOOL_LINK_MODE_1000baseT_Full_BIT]             = "1000baset-full",
-        [ETHTOOL_LINK_MODE_Autoneg_BIT]                    = "autonegotiation",
-        [ETHTOOL_LINK_MODE_TP_BIT]                         = "tp",
-        [ETHTOOL_LINK_MODE_AUI_BIT]                        = "aui",
-        [ETHTOOL_LINK_MODE_MII_BIT]                        = "mii",
-        [ETHTOOL_LINK_MODE_FIBRE_BIT]                      = "fibre",
-        [ETHTOOL_LINK_MODE_BNC_BIT]                        = "bnc",
-        [ETHTOOL_LINK_MODE_10000baseT_Full_BIT]            = "10000baset-full",
-        [ETHTOOL_LINK_MODE_Pause_BIT]                      = "pause",
-        [ETHTOOL_LINK_MODE_Asym_Pause_BIT]                 = "asym-pause",
-        [ETHTOOL_LINK_MODE_2500baseX_Full_BIT]             = "2500basex-full",
-        [ETHTOOL_LINK_MODE_Backplane_BIT]                  = "backplane",
-        [ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]            = "1000basekx-full",
-        [ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]          = "10000basekx4-full",
-        [ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]           = "10000basekr-full",
-        [ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]             = "10000baser-fec",
-        [ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]         = "20000basemld2-full",
-        [ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]          = "20000basekr2-full",
-        [ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]          = "40000basekr4-full",
-        [ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]          = "40000basecr4-full",
-        [ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]          = "40000basesr4-full",
-        [ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]          = "40000baselr4-full",
-        [ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]          = "56000basekr4-full",
-        [ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]          = "56000basecr4-full",
-        [ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]          = "56000basesr4-full",
-        [ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]          = "56000baselr4-full",
-        [ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]           = "25000basecr-full",
-        [ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]           = "25000basekr-full",
-        [ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]           = "25000basesr-full",
-        [ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]          = "50000basecr2-full",
-        [ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]          = "50000basekr2-full",
-        [ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]         = "100000basekr4-full",
-        [ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]         = "100000basesr4-full",
-        [ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]         = "100000basecr4-full",
-        [ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT]     = "100000baselr4-er4-full",
-        [ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]          = "50000basesr2-full",
-        [ETHTOOL_LINK_MODE_1000baseX_Full_BIT]             = "1000basex-full",
-        [ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]           = "10000basecr-full",
-        [ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]           = "10000basesr-full",
-        [ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]           = "10000baselr-full",
-        [ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]          = "10000baselrm-full",
-        [ETHTOOL_LINK_MODE_10000baseER_Full_BIT]           = "10000baseer-full",
-        [ETHTOOL_LINK_MODE_2500baseT_Full_BIT]             = "2500baset-full",
-        [ETHTOOL_LINK_MODE_5000baseT_Full_BIT]             = "5000baset-full",
-        [ETHTOOL_LINK_MODE_FEC_NONE_BIT]                   = "fec-none",
-        [ETHTOOL_LINK_MODE_FEC_RS_BIT]                     = "fec-rs",
-        [ETHTOOL_LINK_MODE_FEC_BASER_BIT]                  = "fec-baser",
-        [ETHTOOL_LINK_MODE_50000baseKR_Full_BIT]           = "50000basekr-full",
-        [ETHTOOL_LINK_MODE_50000baseSR_Full_BIT]           = "50000basesr-full",
-        [ETHTOOL_LINK_MODE_50000baseCR_Full_BIT]           = "50000basecr-full",
-        [ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT]     = "50000baselr-er-fr-full",
-        [ETHTOOL_LINK_MODE_50000baseDR_Full_BIT]           = "50000basedr-full",
-        [ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT]         = "100000basekr2-full",
-        [ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT]         = "100000basesr2-full",
-        [ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT]         = "100000basecr2-full",
-        [ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT] = "100000baselr2-er2-fr2-full",
-        [ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT]         = "100000basedr2-full",
-        [ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT]         = "200000basekr4-full",
-        [ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT]         = "200000basesr4-full",
-        [ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT] = "200000baselr4-er4-fr4-full",
-        [ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT]         = "200000basedr4-full",
-        [ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT]         = "200000basecr4-full",
-        [ETHTOOL_LINK_MODE_100baseT1_Full_BIT]             = "100baset1-full",
-        [ETHTOOL_LINK_MODE_1000baseT1_Full_BIT]            = "1000baset1-full",
-        [ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT]         = "400000basekr8-full",
-        [ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT]         = "400000basesr8-full",
-        [ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT] = "400000baselr8-er8-fr8-full",
-        [ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT]         = "400000basedr8-full",
-        [ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT]         = "400000basecr8-full",
-        [ETHTOOL_LINK_MODE_FEC_LLRS_BIT]                   = "fec-llrs",
-        [ETHTOOL_LINK_MODE_100000baseKR_Full_BIT]          = "100000basekr-full",
-        [ETHTOOL_LINK_MODE_100000baseSR_Full_BIT]          = "100000basesr-full",
-        [ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT]    = "100000baselr-er-fr-full",
-        [ETHTOOL_LINK_MODE_100000baseCR_Full_BIT]          = "100000basecr-full",
-        [ETHTOOL_LINK_MODE_100000baseDR_Full_BIT]          = "100000basedr-full",
-        [ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT]         = "200000basekr2-full",
-        [ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT]         = "200000basesr2-full",
-        [ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT] = "200000baselr2-er2-fr2-full",
-        [ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT]         = "200000basedr2-full",
-        [ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT]         = "200000basecr2-full",
-        [ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT]         = "400000basekr4-full",
-        [ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT]         = "400000basesr4-full",
-        [ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT] = "400000baselr4-er4-fr4-full",
-        [ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT]         = "400000basedr4-full",
-        [ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT]         = "400000basecr4-full",
-        [ETHTOOL_LINK_MODE_100baseFX_Half_BIT]             = "100basefx-half",
-        [ETHTOOL_LINK_MODE_100baseFX_Full_BIT]             = "100basefx-full",
+#  include "ethtool-link-mode.h"
 };
 /* Make sure the array is large enough to fit all bits */
 assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < N_ADVERTISE);
index 84dd444d33864124e3f57fe52315c32c9d0abe48..5303cd750463e7b26b698fd2d2a6aa8fb6c1434e 100644 (file)
@@ -8,7 +8,7 @@
 #include "conf-parser.h"
 #include "ether-addr-util.h"
 
-#define N_ADVERTISE 3
+#define N_ADVERTISE 4
 
 /* we can't use DUPLEX_ prefix, as it
  * clashes with <linux/ethtool.h> */
index 49c5fe5c05bbcb7831606f5ab6c4563b4431e49b..44ed3199222f8a3ebe0f57da5a793c5fece3ccf5 100644 (file)
@@ -235,7 +235,7 @@ static int write_fsck_sysroot_service(
                 "Type=oneshot\n"
                 "RemainAfterExit=yes\n"
                 "ExecStart=" SYSTEMD_FSCK_PATH " %7$s\n"
-                "TimeoutSec=0\n",
+                "TimeoutSec=infinity\n",
                 program_invocation_short_name,
                 escaped,
                 unit,
@@ -530,7 +530,7 @@ int generator_hook_up_mkswap(
                 "Type=oneshot\n"
                 "RemainAfterExit=yes\n"
                 "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
-                "TimeoutSec=0\n",
+                "TimeoutSec=infinity\n",
                 program_invocation_short_name,
                 where_unit,
                 escaped);
@@ -619,7 +619,7 @@ int generator_hook_up_mkfs(
                 "Type=oneshot\n"
                 "RemainAfterExit=yes\n"
                 "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
-                "TimeoutSec=0\n",
+                "TimeoutSec=infinity\n",
                 program_invocation_short_name,
                 fsck_unit,
                 where_unit,
@@ -801,7 +801,7 @@ int generator_write_cryptsetup_service_section(
                 "[Service]\n"
                 "Type=oneshot\n"
                 "RemainAfterExit=yes\n"
-                "TimeoutSec=0\n"          /* The binary handles timeouts on its own */
+                "TimeoutSec=infinity\n"   /* The binary handles timeouts on its own */
                 "KeyringMode=shared\n"    /* Make sure we can share cached keys among instances */
                 "OOMScoreAdjust=500\n"    /* Unlocking can allocate a lot of memory if Argon2 is used */
                 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
index a2fbcd7078d3a9ad75a26c4d2ad1583cc4750c44..59b678c424d8548db724d2e3b60b588fe8a41c4a 100644 (file)
@@ -408,7 +408,7 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) {
                 return -errno;
         fwrite(&h, sizeof(struct trie_header_f), 1, f);
 
-        r = flink_tmpfile(f, filename_tmp, filename, /* replace= */ true);
+        r = flink_tmpfile(f, filename_tmp, filename, LINK_TMPFILE_REPLACE|LINK_TMPFILE_SYNC);
         if (r < 0)
                 return r;
 
index 26d99a5fba0f59ad7e29730b94edd610eed6c54f..417d17df347bc39f35c9e91c972fe260f26083fe 100644 (file)
@@ -4642,10 +4642,20 @@ int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFl
         JsonVariant **p = ASSERT_PTR(userdata);
         assert(variant);
 
+        /* Takes a reference */
         JSON_VARIANT_REPLACE(*p, json_variant_ref(variant));
         return 0;
 }
 
+int json_dispatch_variant_noref(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
+        JsonVariant **p = ASSERT_PTR(userdata);
+        assert(variant);
+
+        /* Doesn't take a reference */
+        *p = variant;
+        return 0;
+}
+
 int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
         uid_t *uid = userdata;
         uint64_t k;
index 5d79472351fa3c1dbab419e4a1350b67d34e2817..1356d0827bd5b98bf4ea69446c516651ed315b35 100644 (file)
@@ -387,6 +387,7 @@ int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags
 int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
+int json_dispatch_variant_noref(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_int64(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_uint64(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
index b34d218c1e2fc6882df4ae4b16d21ce682aff9b7..d34e2c1dd9214136062006a0e78b434f596993d4 100644 (file)
@@ -154,7 +154,6 @@ shared_sources = files(
         'tomoyo-util.c',
         'tpm2-util.c',
         'udev-util.c',
-        'uid-alloc-range.c',
         'user-record-nss.c',
         'user-record-show.c',
         'user-record.c',
@@ -271,6 +270,24 @@ target2 = custom_target(
 shared_generated_gperf_headers = [target1, target2]
 shared_sources += shared_generated_gperf_headers
 
+fname = 'ethtool-link-mode.h'
+ethtool_link_mode_h = custom_target(
+        fname,
+        input : ['ethtool-link-mode.py', 'linux/ethtool.h'],
+        output : fname,
+        command : [python, '@INPUT0@', '--header', cpp, '@INPUT1@'],
+        capture : true)
+shared_sources += ethtool_link_mode_h
+
+fname = 'ethtool-link-mode.xml'
+ethtool_link_mode_xml = custom_target(
+        fname,
+        input : ['ethtool-link-mode.py', 'linux/ethtool.h'],
+        output : fname,
+        command : [python, '@INPUT0@', '--xml', cpp, '@INPUT1@'],
+        capture : true)
+man_page_depends += ethtool_link_mode_xml
+
 libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag)
 
 libshared_deps = [threads,
@@ -296,6 +313,7 @@ libshared_deps = [threads,
                   versiondep]
 
 libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
+libshared_build_dir = meson.current_build_dir()
 
 libshared_static = static_library(
         libshared_name,
index 8e459f9d693d83d2c424700487df7ebfaf22ea46..4664215e906204123587d7b3b63e0b0f78aa5861 100644 (file)
@@ -228,7 +228,7 @@ static int rm_rf_inner_child(
                 if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) {
                         /* This could be a subvolume, try to remove it */
 
-                        r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
+                        r = btrfs_subvol_remove_at(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                         if (r < 0) {
                                 if (!IN_SET(r, -ENOTTY, -EINVAL))
                                         return r;
@@ -425,10 +425,11 @@ static int rm_rf_children_impl(
         return ret;
 }
 
-int rm_rf(const char *path, RemoveFlags flags) {
+int rm_rf_at(int dir_fd, const char *path, RemoveFlags flags) {
         mode_t old_mode;
         int fd, r, q = 0;
 
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
         assert(path);
 
         /* For now, don't support dropping subvols when also only dropping directories, since we can't do
@@ -438,14 +439,13 @@ int rm_rf(const char *path, RemoveFlags flags) {
 
         /* We refuse to clean the root file system with this call. This is extra paranoia to never cause a
          * really seriously broken system. */
-        if (path_equal_or_inode_same(path, "/", AT_SYMLINK_NOFOLLOW))
+        if (path_is_root_at(dir_fd, path) > 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
-                                       "Attempted to remove entire root file system (\"%s\"), and we can't allow that.",
-                                       path);
+                                       "Attempted to remove entire root file system, and we can't allow that.");
 
         if (FLAGS_SET(flags, REMOVE_SUBVOLUME | REMOVE_ROOT | REMOVE_PHYSICAL)) {
                 /* Try to remove as subvolume first */
-                r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
+                r = btrfs_subvol_remove_at(dir_fd, path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                 if (r >= 0)
                         return r;
 
@@ -458,13 +458,13 @@ int rm_rf(const char *path, RemoveFlags flags) {
                 /* Not btrfs or not a subvolume */
         }
 
-        fd = openat_harder(AT_FDCWD, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode);
+        fd = openat_harder(dir_fd, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode);
         if (fd >= 0) {
                 /* We have a dir */
                 r = rm_rf_children_impl(fd, flags, NULL, old_mode);
 
                 if (FLAGS_SET(flags, REMOVE_ROOT))
-                        q = RET_NERRNO(rmdir(path));
+                        q = RET_NERRNO(unlinkat(dir_fd, path, AT_REMOVEDIR));
         } else {
                 r = fd;
                 if (FLAGS_SET(flags, REMOVE_MISSING_OK) && r == -ENOENT)
@@ -479,8 +479,9 @@ int rm_rf(const char *path, RemoveFlags flags) {
                 if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
                         struct statfs s;
 
-                        if (statfs(path, &s) < 0)
-                                return -errno;
+                        r = xstatfsat(dir_fd, path, &s);
+                        if (r < 0)
+                                return r;
                         if (is_physical_fs(&s))
                                 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
                                                        "Attempted to remove files from a disk file system under \"%s\", refusing.",
@@ -488,7 +489,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
                 }
 
                 r = 0;
-                q = RET_NERRNO(unlink(path));
+                q = RET_NERRNO(unlinkat(dir_fd, path, 0));
         }
 
         if (r < 0)
index 24fd9a2aa2d2650984ac81cde2f4be13604ba658..9d93692e0a6e531123d078365a7efbb89b4d5947 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <fcntl.h>
 #include <sys/stat.h>
 
 #include "alloc-util.h"
@@ -26,7 +27,10 @@ int fstatat_harder(int dfd,
 
 int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
 int rm_rf_child(int fd, const char *name, RemoveFlags flags);
-int rm_rf(const char *path, RemoveFlags flags);
+int rm_rf_at(int dir_fd, const char *path, RemoveFlags flags);
+static inline int rm_rf(const char *path, RemoveFlags flags) {
+        return rm_rf_at(AT_FDCWD, path, flags);
+}
 
 /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
 static inline char *rm_rf_physical_and_free(char *p) {
index 9d1a21360fdc34552d574e0ad3f73094b9e472ed..5396062a8be026dd37cb2aacd673768d4ab2d4a5 100644 (file)
@@ -131,6 +131,20 @@ int serialize_strv(FILE *f, const char *key, char **l) {
         return ret;
 }
 
+int deserialize_strv(char ***l, const char *value) {
+        ssize_t unescaped_len;
+        char *unescaped;
+
+        assert(l);
+        assert(value);
+
+        unescaped_len = cunescape(value, 0, &unescaped);
+        if (unescaped_len < 0)
+                return unescaped_len;
+
+        return strv_consume(l, unescaped);
+}
+
 int deserialize_usec(const char *value, usec_t *ret) {
         int r;
 
index 6d4f1ef4181bbfe7e13ed349ab242e54e5db5674..8fdc6dc304ebff69a60bc2482bef0d4fb0773d6a 100644 (file)
@@ -23,5 +23,6 @@ static inline int serialize_bool(FILE *f, const char *key, bool b) {
 int deserialize_usec(const char *value, usec_t *timestamp);
 int deserialize_dual_timestamp(const char *value, dual_timestamp *t);
 int deserialize_environment(const char *value, char ***environment);
+int deserialize_strv(char ***l, const char *value);
 
 int open_serialization_fd(const char *ident);
index 4fd129b27efe5815e822e3a4c5f531e17ce02769..dcc233ca6f3d9a75029ba9887a6b51f5aa7a2248 100644 (file)
@@ -723,6 +723,14 @@ static bool location_is_resume_device(const HibernateLocation *location, dev_t s
  * Attempt to find the hibernation location by parsing /proc/swaps, /sys/power/resume, and
  * /sys/power/resume_offset.
  *
+ * Beware:
+ *  Never use a device or file as location that hasn't been somehow specified by a user that would also be
+ *  entrusted with full system memory access (for example via /sys/power/resume) or that isn't an already
+ *  active swap area!
+ *  Otherwise various security attacks might become possible, for example an attacker could silently attach
+ *  such a device and circumvent full disk encryption when it would be automatically used for hibernation.
+ *  Also, having a swap area on top of encryption is not per se enough to protect from all such attacks.
+ *
  * Returns:
  *  1 - Values are set in /sys/power/resume and /sys/power/resume_offset.
  *      ret_hibernate_location will represent matching /proc/swap entry if identified or NULL if not.
index e115dff5064f2bd9912a23629bed719647682a25..0ba57627615d89b773d51e613d4e6348bd232170 100644 (file)
@@ -180,7 +180,7 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) {
 
         a.type = type;
 
-        fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
+        fd = socket_address_listen(&a, type | flags, SOMAXCONN_DELUXE, SOCKET_ADDRESS_DEFAULT,
                                    NULL, false, false, false, 0755, 0644, NULL);
         if (fd < 0 || log_get_max_level() >= log_level) {
                 _cleanup_free_ char *p = NULL;
index 680cc726c3a31b198c31f7bab12e12fd5679e611..9694a36d8f851ef1464ff100b2236235be7ec316 100644 (file)
@@ -52,6 +52,8 @@ static TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySe
 static TSS2_RC (*sym_Esys_ReadPublic)(ESYS_CONTEXT *esysContext, ESYS_TR objectHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_PUBLIC **outPublic, TPM2B_NAME **name, TPM2B_NAME **qualifiedName) = NULL;
 static TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL;
 static TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL;
+static TSS2_RC (*sym_Esys_TestParms)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPMT_PUBLIC_PARMS *parameters) = NULL;
+static TSS2_RC (*sym_Esys_TR_Close)(ESYS_CONTEXT *esys_context, ESYS_TR *rsrc_handle) = NULL;
 static TSS2_RC (*sym_Esys_TR_Deserialize)(ESYS_CONTEXT *esys_context, uint8_t const *buffer, size_t buffer_size, ESYS_TR *esys_handle) = NULL;
 static TSS2_RC (*sym_Esys_TR_FromTPMPublic)(ESYS_CONTEXT *esysContext, TPM2_HANDLE tpm_handle, ESYS_TR optionalSession1, ESYS_TR optionalSession2, ESYS_TR optionalSession3, ESYS_TR *object) = NULL;
 static TSS2_RC (*sym_Esys_TR_GetName)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_NAME **name) = NULL;
@@ -98,6 +100,8 @@ int dlopen_tpm2(void) {
                         DLSYM_ARG(Esys_ReadPublic),
                         DLSYM_ARG(Esys_StartAuthSession),
                         DLSYM_ARG(Esys_Startup),
+                        DLSYM_ARG(Esys_TestParms),
+                        DLSYM_ARG(Esys_TR_Close),
                         DLSYM_ARG(Esys_TR_Deserialize),
                         DLSYM_ARG(Esys_TR_FromTPMPublic),
                         DLSYM_ARG(Esys_TR_GetName),
@@ -133,6 +137,279 @@ static inline void Esys_Freep(void *p) {
                 sym_Esys_Free(*(void**) p);
 }
 
+/* Get a specific TPM capability (or capabilities).
+ *
+ * Returns 0 if there are no more capability properties of the requested type, or 1 if there are more, or < 0
+ * on any error. Both 0 and 1 indicate this completed successfully, but do not indicate how many capability
+ * properties were provided in 'ret_capability_data'. To find the number of provided properties, check the
+ * specific type's 'count' field (e.g. for TPM2_CAP_ALGS, check ret_capability_data->algorithms.count).
+ *
+ * This calls TPM2_GetCapability() and does not alter the provided data, so it is important to understand how
+ * that TPM function works. It is recommended to check the TCG TPM specification Part 3 ("Commands") section
+ * on TPM2_GetCapability() for full details, but a short summary is: if this returns 0, all available
+ * properties have been provided in ret_capability_data, or no properties were available. If this returns 1,
+ * there are between 1 and "count" properties provided in ret_capability_data, and there are more available.
+ * Note that this may provide less than "count" properties even if the TPM has more available. Also, each
+ * capability category may have more specific requirements than described here; see the spec for exact
+ * details. */
+static int tpm2_get_capability(
+                Tpm2Context *c,
+                TPM2_CAP capability,
+                uint32_t property,
+                uint32_t count,
+                TPMU_CAPABILITIES *ret_capability_data) {
+
+        _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *capabilities = NULL;
+        TPMI_YES_NO more;
+        TSS2_RC rc;
+
+        assert(c);
+
+        log_debug("Getting TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 " count %" PRIu32 ".",
+                  capability, property, count);
+
+        rc = sym_Esys_GetCapability(
+                        c->esys_context,
+                        ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        capability,
+                        property,
+                        count,
+                        &more,
+                        &capabilities);
+        if (rc != TSS2_RC_SUCCESS)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "Failed to get TPM2 capability 0x%04" PRIx32 " property 0x%04" PRIx32 ": %s",
+                                       capability, property, sym_Tss2_RC_Decode(rc));
+
+        if (capabilities->capability != capability)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "TPM provided wrong capability: 0x%04" PRIx32 " instead of 0x%04" PRIx32 ".",
+                                       capabilities->capability, capability);
+
+        if (ret_capability_data)
+                *ret_capability_data = capabilities->data;
+
+        return more == TPM2_YES;
+}
+
+static int tpm2_cache_capabilities(Tpm2Context *c) {
+        TPMU_CAPABILITIES capability;
+        int r;
+
+        assert(c);
+
+        /* Cache the PCR capabilities, which are safe to cache, as the only way they can change is
+         * TPM2_PCR_Allocate(), which changes the allocation after the next _TPM_Init(). If the TPM is
+         * reinitialized while we are using it, all our context and sessions will be invalid, so we can
+         * safely assume the TPM PCR allocation will not change while we are using it. */
+        r = tpm2_get_capability(
+                        c,
+                        TPM2_CAP_PCRS,
+                        /* property= */ 0,
+                        /* count= */ 1,
+                        &capability);
+        if (r < 0)
+                return r;
+        if (r == 1)
+                /* This should never happen. Part 3 ("Commands") of the TCG TPM2 spec in the section for
+                 * TPM2_GetCapability states: "TPM_CAP_PCRS – Returns the current allocation of PCR in a
+                 * TPML_PCR_SELECTION. The property parameter shall be zero. The TPM will always respond to
+                 * this command with the full PCR allocation and moreData will be NO." */
+                log_warning("TPM bug: reported multiple PCR sets; using only first set.");
+        c->capability_pcrs = capability.assignedPCR;
+
+        return 0;
+}
+
+#define tpm2_capability_pcrs(c) ((c)->capability_pcrs)
+
+/* Get the TPMA_ALGORITHM for a TPM2_ALG_ID.
+ *
+ * Returns 1 if the TPM supports the algorithm and the TPMA_ALGORITHM is provided, or 0 if the TPM does not
+ * support the algorithm, or < 0 for any errors. */
+static int tpm2_get_capability_alg(Tpm2Context *c, TPM2_ALG_ID alg, TPMA_ALGORITHM *ret) {
+        TPMU_CAPABILITIES capability;
+        int r;
+
+        assert(c);
+
+        /* The spec explicitly states the TPM2_ALG_ID should be cast to uint32_t. */
+        r = tpm2_get_capability(c, TPM2_CAP_ALGS, (uint32_t) alg, 1, &capability);
+        if (r < 0)
+                return r;
+
+        TPML_ALG_PROPERTY algorithms = capability.algorithms;
+        if (algorithms.count == 0 || algorithms.algProperties[0].alg != alg) {
+                log_debug("TPM does not support alg 0x%02" PRIx16 ".", alg);
+                return 0;
+        }
+
+        if (ret)
+                *ret = algorithms.algProperties[0].algProperties;
+
+        return 1;
+}
+
+/* Returns 1 if the TPM supports the alg, 0 if the TPM does not support the alg, or < 0 for any error. */
+int tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg) {
+        return tpm2_get_capability_alg(c, alg, NULL);
+}
+
+/* Returns 1 if the TPM supports the ECC curve, 0 if not, or < 0 for any error. */
+static int tpm2_supports_ecc_curve(Tpm2Context *c, TPM2_ECC_CURVE curve) {
+        TPMU_CAPABILITIES capability;
+        int r;
+
+        /* The spec explicitly states the TPM2_ECC_CURVE should be cast to uint32_t. */
+        r = tpm2_get_capability(c, TPM2_CAP_ECC_CURVES, (uint32_t) curve, 1, &capability);
+        if (r < 0)
+                return r;
+
+        TPML_ECC_CURVE eccCurves = capability.eccCurves;
+        if (eccCurves.count == 0 || eccCurves.eccCurves[0] != curve) {
+                log_debug("TPM does not support ECC curve 0x%02" PRIx16 ".", curve);
+                return 0;
+        }
+
+        return 1;
+}
+
+/* Query the TPM for populated handles.
+ *
+ * This provides an array of handle indexes populated in the TPM, starting at the requested handle. The array will
+ * contain only populated handle addresses (which might not include the requested handle). The number of
+ * handles will be no more than the 'max' number requested. This will not search past the end of the handle
+ * range (i.e. handle & 0xff000000).
+ *
+ * Returns 0 if all populated handles in the range (starting at the requested handle) were provided (or no
+ * handles were in the range), or 1 if there are more populated handles in the range, or < 0 on any error. */
+static int tpm2_get_capability_handles(
+                Tpm2Context *c,
+                TPM2_HANDLE start,
+                size_t max,
+                TPM2_HANDLE **ret_handles,
+                size_t *ret_n_handles) {
+
+        _cleanup_free_ TPM2_HANDLE *handles = NULL;
+        size_t n_handles = 0;
+        TPM2_HANDLE current = start;
+        int r = 0;
+
+        assert(c);
+        assert(ret_handles);
+        assert(ret_n_handles);
+
+        while (max > 0) {
+                TPMU_CAPABILITIES capability;
+                r = tpm2_get_capability(c, TPM2_CAP_HANDLES, current, (uint32_t) max, &capability);
+                if (r < 0)
+                        return r;
+
+                TPML_HANDLE handle_list = capability.handles;
+                if (handle_list.count == 0)
+                        break;
+
+                assert(handle_list.count <= max);
+
+                if (n_handles > SIZE_MAX - handle_list.count)
+                        return log_oom();
+
+                if (!GREEDY_REALLOC(handles, n_handles + handle_list.count))
+                        return log_oom();
+
+                memcpy_safe(&handles[n_handles], handle_list.handle, sizeof(handles[0]) * handle_list.count);
+
+                max -= handle_list.count;
+                n_handles += handle_list.count;
+
+                /* Update current to the handle index after the last handle in the list. */
+                current = handles[n_handles - 1] + 1;
+
+                if (r == 0)
+                        /* No more handles in this range. */
+                        break;
+        }
+
+        *ret_handles = TAKE_PTR(handles);
+        *ret_n_handles = n_handles;
+
+        return r;
+}
+
+#define TPM2_HANDLE_RANGE(h) ((TPM2_HANDLE)((h) & TPM2_HR_RANGE_MASK))
+#define TPM2_HANDLE_TYPE(h) ((TPM2_HT)(TPM2_HANDLE_RANGE(h) >> TPM2_HR_SHIFT))
+
+/* Returns 1 if the handle is populated in the TPM, 0 if not, and < 0 on any error. */
+static int tpm2_get_capability_handle(Tpm2Context *c, TPM2_HANDLE handle) {
+        _cleanup_free_ TPM2_HANDLE *handles = NULL;
+        size_t n_handles = 0;
+        int r;
+
+        r = tpm2_get_capability_handles(c, handle, 1, &handles, &n_handles);
+        if (r < 0)
+                return r;
+
+        return n_handles == 0 ? false : handles[0] == handle;
+}
+
+/* Returns 1 if the TPM supports the parms, or 0 if the TPM does not support the parms. */
+bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARMS *parms) {
+        TSS2_RC rc;
+
+        assert(c);
+        assert(parms);
+
+        TPMT_PUBLIC_PARMS parameters = {
+                .type = alg,
+                .parameters = *parms,
+        };
+
+        rc = sym_Esys_TestParms(c->esys_context, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parameters);
+        if (rc != TSS2_RC_SUCCESS)
+                /* The spec says if the parms are not supported the TPM returns "...the appropriate
+                 * unmarshaling error if a parameter is not valid". Since the spec (currently) defines 15
+                 * unmarshaling errors, instead of checking for them all here, let's just assume any error
+                 * indicates unsupported parms, and log the specific error text. */
+                log_debug("TPM does not support tested parms: %s", sym_Tss2_RC_Decode(rc));
+
+        return rc == TSS2_RC_SUCCESS;
+}
+
+static inline bool tpm2_supports_tpmt_public(Tpm2Context *c, const TPMT_PUBLIC *public) {
+        assert(c);
+        assert(public);
+
+        return tpm2_test_parms(c, public->type, &public->parameters);
+}
+
+static inline bool tpm2_supports_tpmt_sym_def_object(Tpm2Context *c, const TPMT_SYM_DEF_OBJECT *parameters) {
+        assert(c);
+        assert(parameters);
+
+        TPMU_PUBLIC_PARMS parms = {
+                .symDetail.sym = *parameters,
+        };
+
+        return tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &parms);
+}
+
+static inline bool tpm2_supports_tpmt_sym_def(Tpm2Context *c, const TPMT_SYM_DEF *parameters) {
+        assert(c);
+        assert(parameters);
+
+        /* Unfortunately, TPMT_SYM_DEF and TPMT_SYM_DEF_OBEJECT are separately defined, even though they are
+         * functionally identical. */
+        TPMT_SYM_DEF_OBJECT object = {
+                .algorithm = parameters->algorithm,
+                .keyBits = parameters->keyBits,
+                .mode = parameters->mode,
+        };
+
+        return tpm2_supports_tpmt_sym_def_object(c, &object);
+}
+
 static Tpm2Context *tpm2_context_free(Tpm2Context *c) {
         if (!c)
                 return NULL;
@@ -148,8 +425,14 @@ static Tpm2Context *tpm2_context_free(Tpm2Context *c) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free);
 
+static const TPMT_SYM_DEF SESSION_TEMPLATE_SYM_AES_128_CFB = {
+        .algorithm = TPM2_ALG_AES,
+        .keyBits.aes = 128,
+        .mode.aes = TPM2_ALG_CFB, /* The spec requires sessions to use CFB. */
+};
+
 int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
-        _cleanup_tpm2_context_ Tpm2Context *context = NULL;
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *context = NULL;
         TSS2_RC rc;
         int r;
 
@@ -255,37 +538,65 @@ int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
                 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                        "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc));
 
+        r = tpm2_cache_capabilities(context);
+        if (r < 0)
+                return r;
+
+        /* We require AES and CFB support for session encryption. */
+        r = tpm2_supports_alg(context, TPM2_ALG_AES);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support AES.");
+
+        r = tpm2_supports_alg(context, TPM2_ALG_CFB);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support CFB.");
+
+        if (!tpm2_supports_tpmt_sym_def(context, &SESSION_TEMPLATE_SYM_AES_128_CFB))
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM does not support AES-128-CFB.");
+
         *ret_context = TAKE_PTR(context);
 
         return 0;
 }
 
-static void tpm2_handle_flush(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle) {
+static void tpm2_handle_cleanup(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle, bool flush) {
+        TSS2_RC rc;
+
         if (!esys_context || esys_handle == ESYS_TR_NONE)
                 return;
 
-        TSS2_RC rc = sym_Esys_FlushContext(esys_context, esys_handle);
+        /* Closing the handle removes its reference from the esys_context, but leaves the corresponding
+         * handle in the actual TPM. Flushing the handle removes its reference from the esys_context as well
+         * as removing its corresponding handle from the actual TPM. */
+        if (flush)
+                rc = sym_Esys_FlushContext(esys_context, esys_handle);
+        else
+                rc = sym_Esys_TR_Close(esys_context, &esys_handle);
         if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called
                                     * in error paths, where we cannot do anything about failures anymore. And
                                     * when it is called in successful codepaths by this time we already did
                                     * what we wanted to do, and got the results we wanted so there's no
                                     * reason to make this fail more loudly than necessary. */
-                log_debug("Failed to flush TPM handle, ignoring: %s", sym_Tss2_RC_Decode(rc));
+                log_debug("Failed to %s TPM handle, ignoring: %s", flush ? "flush" : "close", sym_Tss2_RC_Decode(rc));
 }
 
 Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle) {
         if (!handle)
                 return NULL;
 
-        _cleanup_tpm2_context_ Tpm2Context *context = (Tpm2Context*)handle->tpm2_context;
-        if (context && !handle->keep)
-                tpm2_handle_flush(context->esys_context, handle->esys_handle);
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *context = (Tpm2Context*)handle->tpm2_context;
+        if (context)
+                tpm2_handle_cleanup(context->esys_context, handle->esys_handle, handle->flush);
 
         return mfree(handle);
 }
 
 int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
-        _cleanup_tpm2_handle_ Tpm2Handle *handle = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
 
         assert(ret_handle);
 
@@ -296,6 +607,7 @@ int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
         *handle = (Tpm2Handle) {
                 .tpm2_context = tpm2_context_ref(context),
                 .esys_handle = ESYS_TR_NONE,
+                .flush = true,
         };
 
         *ret_handle = TAKE_PTR(handle);
@@ -303,6 +615,81 @@ int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
         return 0;
 }
 
+/* Create a Tpm2Handle object that references a pre-existing handle in the TPM, at the TPM2_HANDLE address
+ * provided. This should be used only for persistent, transient, or NV handles. Returns 1 on success, 0 if
+ * the requested handle is not present in the TPM, or < 0 on error. */
+static int tpm2_esys_handle_from_tpm_handle(
+                Tpm2Context *c,
+                const Tpm2Handle *session,
+                TPM2_HANDLE tpm_handle,
+                Tpm2Handle **ret_handle) {
+
+        TSS2_RC rc;
+        int r;
+
+        assert(c);
+        assert(tpm_handle > 0);
+        assert(ret_handle);
+
+        /* Let's restrict this, at least for now, to allow only some handle types. */
+        switch (TPM2_HANDLE_TYPE(tpm_handle)) {
+        case TPM2_HT_PERSISTENT:
+        case TPM2_HT_NV_INDEX:
+        case TPM2_HT_TRANSIENT:
+                break;
+        case TPM2_HT_PCR:
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Refusing to create ESYS handle for PCR handle 0x%08" PRIx32 ".",
+                                       tpm_handle);
+        case TPM2_HT_HMAC_SESSION:
+        case TPM2_HT_POLICY_SESSION:
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Refusing to create ESYS handle for session handle 0x%08" PRIx32 ".",
+                                       tpm_handle);
+        case TPM2_HT_PERMANENT: /* Permanent handles are defined, e.g. ESYS_TR_RH_OWNER. */
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Refusing to create ESYS handle for permanent handle 0x%08" PRIx32 ".",
+                                       tpm_handle);
+        default:
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Refusing to create ESYS handle for unknown handle 0x%08" PRIx32 ".",
+                                       tpm_handle);
+        }
+
+        r = tpm2_get_capability_handle(c, tpm_handle);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                log_debug("TPM handle 0x%08" PRIx32 " not populated.", tpm_handle);
+                *ret_handle = NULL;
+                return 0;
+        }
+
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+        r = tpm2_handle_new(c, &handle);
+        if (r < 0)
+                return r;
+
+        /* Since we didn't create this handle in the TPM (this is only creating an ESYS_TR handle for the
+         * pre-existing TPM handle), we shouldn't flush (or evict) it on cleanup. */
+        handle->flush = false;
+
+        rc = sym_Esys_TR_FromTPMPublic(
+                        c->esys_context,
+                        tpm_handle,
+                        session ? session->esys_handle : ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        &handle->esys_handle);
+        if (rc != TSS2_RC_SUCCESS)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
+
+        *ret_handle = TAKE_PTR(handle);
+
+        return 1;
+}
+
 #define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
 
 static int tpm2_credit_random(Tpm2Context *c) {
@@ -363,102 +750,197 @@ static int tpm2_credit_random(Tpm2Context *c) {
         return 0;
 }
 
-const TPM2B_PUBLIC *tpm2_get_primary_template(Tpm2SRKTemplateFlags flags) {
+static int tpm2_read_public(
+                Tpm2Context *c,
+                const Tpm2Handle *session,
+                const Tpm2Handle *handle,
+                TPM2B_PUBLIC **ret_public,
+                TPM2B_NAME **ret_name,
+                TPM2B_NAME **ret_qname) {
 
-        /*
-         * Set up array so flags can be used directly as an input.
-         *
-         * Templates for SRK come from the spec:
-         *   - https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf
-         *
-         * However, note their is some lore here. On Linux, the SRK has it's unique field set to size 0 and
-         * on Windows the SRK has their unique data set to keyLen in bytes of zeros.
-         */
-        assert(flags >= 0);
-        assert(flags <= _TPM2_SRK_TEMPLATE_MAX);
-
-        static const TPM2B_PUBLIC templ[_TPM2_SRK_TEMPLATE_MAX + 1] = {
-                /* index 0 RSA old */
-                [0] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_RSA,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
-                                .parameters.rsaDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .keyBits = 2048,
-                                },
+        TSS2_RC rc;
+
+        assert(c);
+        assert(handle);
+
+        rc = sym_Esys_ReadPublic(
+                        c->esys_context,
+                        handle->esys_handle,
+                        session ? session->esys_handle : ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        ESYS_TR_NONE,
+                        ret_public,
+                        ret_name,
+                        ret_qname);
+        if (rc != TSS2_RC_SUCCESS)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "Failed to read public info: %s", sym_Tss2_RC_Decode(rc));
+
+        return 0;
+}
+
+/* Get one of the legacy primary key templates.
+ *
+ * The legacy templates should only be used for older sealed data that did not use the SRK. Instead of a
+ * persistent SRK, a transient key was created to seal the data and then flushed; and the exact same template
+ * must be used to recreate the same transient key to unseal the data. The alg parameter must be TPM2_ALG_RSA
+ * or TPM2_ALG_ECC. This does not check if the alg is actually supported on this TPM. */
+static int tpm2_get_legacy_template(TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
+        /* Do not modify. */
+        static const TPMT_PUBLIC legacy_ecc = {
+                .type = TPM2_ALG_ECC,
+                .nameAlg = TPM2_ALG_SHA256,
+                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
+                .parameters.eccDetail = {
+                        .symmetric = {
+                                .algorithm = TPM2_ALG_AES,
+                                .keyBits.aes = 128,
+                                .mode.aes = TPM2_ALG_CFB,
                         },
+                        .scheme.scheme = TPM2_ALG_NULL,
+                        .curveID = TPM2_ECC_NIST_P256,
+                        .kdf.scheme = TPM2_ALG_NULL,
                 },
-                [TPM2_SRK_TEMPLATE_ECC] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_ECC,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
-                                .parameters.eccDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .curveID = TPM2_ECC_NIST_P256,
-                                        .kdf.scheme = TPM2_ALG_NULL,
-                                },
+        };
+
+        /* Do not modify. */
+        static const TPMT_PUBLIC legacy_rsa = {
+                .type = TPM2_ALG_RSA,
+                .nameAlg = TPM2_ALG_SHA256,
+                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
+                .parameters.rsaDetail = {
+                        .symmetric = {
+                                .algorithm = TPM2_ALG_AES,
+                                .keyBits.aes = 128,
+                                .mode.aes = TPM2_ALG_CFB,
                         },
+                        .scheme.scheme = TPM2_ALG_NULL,
+                        .keyBits = 2048,
                 },
-                [TPM2_SRK_TEMPLATE_NEW_STYLE] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_RSA,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_USERWITHAUTH|TPMA_OBJECT_NODA,
-                                .parameters.rsaDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .keyBits = 2048,
-                                },
-                        },
+        };
+
+        assert(ret_template);
+
+        if (alg == TPM2_ALG_ECC)
+                *ret_template = legacy_ecc;
+        else if (alg == TPM2_ALG_RSA)
+                *ret_template = legacy_rsa;
+        else
+                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Unsupported legacy SRK alg: 0x%x", alg);
+
+        return 0;
+}
+
+/* Get a Storage Root Key (SRK) template.
+ *
+ * The SRK template values are recommended by the "TCG TPM v2.0 Provisioning Guidance" document in section
+ * 7.5.1 "Storage Primary Key (SRK) Templates", referencing "TCG EK Credential Profile for TPM Family 2.0".
+ * The EK Credential Profile version 2.0 provides only a single template each for RSA and ECC, while later EK
+ * Credential Profile versions provide more templates, and keep the original templates as "L-1" (for RSA) and
+ * "L-2" (for ECC).
+ *
+ * https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance
+ * https://trustedcomputinggroup.org/resource/http-trustedcomputinggroup-org-wp-content-uploads-tcg-ek-credential-profile
+ *
+ * These templates are only needed to create a new persistent SRK (or a new transient key that is
+ * SRK-compatible). Preferably, the TPM should contain a shared SRK located at the reserved shared SRK handle
+ * (see TPM2_SRK_HANDLE and tpm2_get_srk() below).
+ *
+ * The alg must be TPM2_ALG_RSA or TPM2_ALG_ECC. Returns error if the requested template is not supported on
+ * this TPM. */
+static int tpm2_get_srk_template(Tpm2Context *c, TPMI_ALG_PUBLIC alg, TPMT_PUBLIC *ret_template) {
+        /* The attributes are the same between ECC and RSA templates. This has the changes specified in the
+         * Provisioning Guidance document, specifically:
+         * TPMA_OBJECT_USERWITHAUTH is added.
+         * TPMA_OBJECT_ADMINWITHPOLICY is removed.
+         * TPMA_OBJECT_NODA is added. */
+        TPMA_OBJECT srk_attributes =
+                        TPMA_OBJECT_DECRYPT |
+                        TPMA_OBJECT_FIXEDPARENT |
+                        TPMA_OBJECT_FIXEDTPM |
+                        TPMA_OBJECT_NODA |
+                        TPMA_OBJECT_RESTRICTED |
+                        TPMA_OBJECT_SENSITIVEDATAORIGIN |
+                        TPMA_OBJECT_USERWITHAUTH;
+
+        /* The symmetric configuration is the same between ECC and RSA templates. */
+        TPMT_SYM_DEF_OBJECT srk_symmetric = {
+                .algorithm = TPM2_ALG_AES,
+                .keyBits.aes = 128,
+                .mode.aes = TPM2_ALG_CFB,
+        };
+
+        /* Both templates have an empty authPolicy as specified by the Provisioning Guidance document. */
+
+        /* From the EK Credential Profile template "L-2". */
+        TPMT_PUBLIC srk_ecc = {
+                .type = TPM2_ALG_ECC,
+                .nameAlg = TPM2_ALG_SHA256,
+                .objectAttributes = srk_attributes,
+                .parameters.eccDetail = {
+                        .symmetric = srk_symmetric,
+                        .scheme.scheme = TPM2_ALG_NULL,
+                        .curveID = TPM2_ECC_NIST_P256,
+                        .kdf.scheme = TPM2_ALG_NULL,
                 },
-                [TPM2_SRK_TEMPLATE_NEW_STYLE|TPM2_SRK_TEMPLATE_ECC] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_ECC,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_USERWITHAUTH|TPMA_OBJECT_NODA,
-                                .parameters.eccDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .curveID = TPM2_ECC_NIST_P256,
-                                        .kdf.scheme = TPM2_ALG_NULL,
-                                },
-                        },
+        };
+
+        /* From the EK Credential Profile template "L-1". */
+        TPMT_PUBLIC srk_rsa = {
+                .type = TPM2_ALG_RSA,
+                .nameAlg = TPM2_ALG_SHA256,
+                .objectAttributes = srk_attributes,
+                .parameters.rsaDetail = {
+                        .symmetric = srk_symmetric,
+                        .scheme.scheme = TPM2_ALG_NULL,
+                        .keyBits = 2048,
                 },
         };
 
-        return &templ[flags];
+        assert(c);
+        assert(ret_template);
+
+        if (alg == TPM2_ALG_ECC) {
+                if (!tpm2_supports_alg(c, TPM2_ALG_ECC))
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "TPM does not support ECC.");
+
+                if (!tpm2_supports_ecc_curve(c, srk_ecc.parameters.eccDetail.curveID))
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "TPM does not support ECC-NIST-P256 curve.");
+
+                if (!tpm2_supports_tpmt_public(c, &srk_ecc))
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "TPM does not support SRK ECC template L-2.");
+
+                *ret_template = srk_ecc;
+                return 0;
+        }
+
+        if (alg == TPM2_ALG_RSA) {
+                if (!tpm2_supports_alg(c, TPM2_ALG_RSA))
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "TPM does not support RSA.");
+
+                if (!tpm2_supports_tpmt_public(c, &srk_rsa))
+                        return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                               "TPM does not support SRK RSA template L-1.");
+
+                *ret_template = srk_rsa;
+                return 0;
+        }
+
+        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported SRK alg: 0x%x.", alg);
 }
 
-/*
- * Why and what is an SRK?
- * TL;DR provides a working space for those without owner auth. The user enrolling
- * the disk may not have access to the TPMs owner hierarchy auth, so they need a
- * working space. This working space is at the defined address of 0x81000001.
- * Details can be found here:
- *   - https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf
- */
-#define SRK_HANDLE UINT32_C(0x81000001)
+/* The SRK handle is defined in the Provisioning Guidance document (see above) in the table "Reserved Handles
+ * for TPM Provisioning Fundamental Elements". The SRK is useful because it is "shared", meaning it has no
+ * authValue nor authPolicy set, and thus may be used by anyone on the system to generate derived keys or
+ * seal secrets. This is useful if the TPM has an auth (password) set for the 'owner hierarchy', which would
+ * prevent users from generating primary transient keys, unless they knew the owner hierarchy auth. See
+ * the Provisioning Guidance document for more details. */
+#define TPM2_SRK_HANDLE UINT32_C(0x81000001)
 
 /*
  * Retrieves the SRK handle if present. Returns 0 if SRK not present, 1 if present
@@ -466,76 +948,40 @@ const TPM2B_PUBLIC *tpm2_get_primary_template(Tpm2SRKTemplateFlags flags) {
  */
 static int tpm2_get_srk(
                 Tpm2Context *c,
-                TPMI_ALG_PUBLIC *ret_alg,
-                Tpm2Handle *ret_primary) {
+                const Tpm2Handle *session,
+                TPM2B_PUBLIC **ret_public,
+                TPM2B_NAME **ret_name,
+                TPM2B_NAME **ret_qname,
+                Tpm2Handle **ret_handle) {
 
-        TPMI_YES_NO more_data;
-        ESYS_TR primary_tr = ESYS_TR_NONE;
-        _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *cap_data = NULL;
+        int r;
 
         assert(c);
-        assert(ret_primary);
-
-        TSS2_RC rc = sym_Esys_GetCapability(c->esys_context,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        TPM2_CAP_HANDLES,
-                        SRK_HANDLE,
-                        1,
-                        &more_data,
-                        &cap_data);
-        if (rc != TSS2_RC_SUCCESS)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
-                                       "Failed to enumerate handles searching for SRK: %s",
-                                       sym_Tss2_RC_Decode(rc));
-
-        /* Did Not find SRK, indicate this by returning 0 */
-        if (cap_data->data.handles.count == 0 || cap_data->data.handles.handle[0] != SRK_HANDLE) {
-                ret_primary->esys_handle = ESYS_TR_NONE;
 
-                if (ret_alg)
-                        *ret_alg = 0;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+        r = tpm2_esys_handle_from_tpm_handle(c, session, TPM2_SRK_HANDLE, &handle);
+        if (r < 0)
+                return r;
+        if (r == 0) { /* SRK not found */
+                if (ret_public)
+                        *ret_public = NULL;
+                if (ret_name)
+                        *ret_name = NULL;
+                if (ret_qname)
+                        *ret_qname = NULL;
+                if (ret_handle)
+                        *ret_handle = NULL;
                 return 0;
         }
 
-        log_debug("Found SRK on TPM.");
-
-        /* convert the raw handle to an ESYS_TR */
-        TPM2_HANDLE handle = cap_data->data.handles.handle[0];
-        rc = sym_Esys_TR_FromTPMPublic(c->esys_context,
-                        handle,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        &primary_tr);
-        if (rc != TSS2_RC_SUCCESS)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
-                                        "Failed to convert ray handle to ESYS_TR for SRK: %s",
-                                        sym_Tss2_RC_Decode(rc));
-
-        /* Get the algorithm if the caller wants it */
-        _cleanup_(Esys_Freep) TPM2B_PUBLIC *out_public = NULL;
-        if (ret_alg) {
-                rc = sym_Esys_ReadPublic(
-                                c->esys_context,
-                                primary_tr,
-                                ESYS_TR_NONE,
-                                ESYS_TR_NONE,
-                                ESYS_TR_NONE,
-                                &out_public,
-                                NULL,
-                                NULL);
-                if (rc != TSS2_RC_SUCCESS)
-                        return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
-                                                "Failed to convert ray handle to ESYS_TR for SRK: %s",
-                                                sym_Tss2_RC_Decode(rc));
+        if (ret_public || ret_name || ret_qname) {
+                r = tpm2_read_public(c, session, handle, ret_public, ret_name, ret_qname);
+                if (r < 0)
+                        return r;
         }
 
-        ret_primary->esys_handle = primary_tr;
-
-        if (ret_alg)
-                 *ret_alg = out_public->publicArea.type;
+        if (ret_handle)
+                *ret_handle = TAKE_PTR(handle);
 
         return 1;
 }
@@ -549,8 +995,7 @@ static int tpm2_make_primary(
 
         static const TPM2B_SENSITIVE_CREATE primary_sensitive = {};
         static const TPML_PCR_SELECTION creation_pcr = {};
-        const TPM2B_PUBLIC *primary_template = NULL;
-        Tpm2SRKTemplateFlags base_flags = use_srk_model ? TPM2_SRK_TEMPLATE_NEW_STYLE : 0;
+        TPM2B_PUBLIC primary_template = { .size = sizeof(TPMT_PUBLIC), };
         _cleanup_(release_lock_file) LockFile srk_lock = LOCK_FILE_INIT;
         TSS2_RC rc;
         usec_t ts;
@@ -564,10 +1009,7 @@ static int tpm2_make_primary(
 
         ts = now(CLOCK_MONOTONIC);
 
-        _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
-        r = tpm2_handle_new(c, &primary);
-        if (r < 0)
-                return r;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *primary = NULL;
 
         /* we only need the SRK lock when making the SRK since its not atomic, transient
          * primary creations don't even matter if they stomp on each other, the TPM will
@@ -581,14 +1023,15 @@ static int tpm2_make_primary(
 
         /* Find existing SRK and use it if present */
         if (use_srk_model) {
-                TPMI_ALG_PUBLIC got_alg = TPM2_ALG_NULL;
-                r = tpm2_get_srk(c, &got_alg, primary);
+                _cleanup_(Esys_Freep) TPM2B_PUBLIC *primary_public = NULL;
+                r = tpm2_get_srk(c, NULL, &primary_public, NULL, NULL, &primary);
                 if (r < 0)
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                                "Failed to establish if SRK is present");
                 if (r == 1) {
                         log_debug("Discovered existing SRK");
 
+                        TPMI_ALG_PUBLIC got_alg = primary_public->publicArea.type;
                         if (alg != 0 && alg != got_alg)
                                 log_warning("Caller asked for specific algorithm %u, but existing SRK is %u, ignoring",
                                             alg, got_alg);
@@ -602,8 +1045,17 @@ static int tpm2_make_primary(
                 log_debug("Did not find SRK, generating...");
         }
 
+        r = tpm2_handle_new(c, &primary);
+        if (r < 0)
+                return r;
+
         if (IN_SET(alg, 0, TPM2_ALG_ECC)) {
-                primary_template = tpm2_get_primary_template(base_flags | TPM2_SRK_TEMPLATE_ECC);
+                if (use_srk_model)
+                        r = tpm2_get_srk_template(c, TPM2_ALG_ECC, &primary_template.publicArea);
+                else
+                        r = tpm2_get_legacy_template(TPM2_ALG_ECC, &primary_template.publicArea);
+                if (r < 0)
+                        return r;
 
                 rc = sym_Esys_CreatePrimary(
                                 c->esys_context,
@@ -612,7 +1064,7 @@ static int tpm2_make_primary(
                                 ESYS_TR_NONE,
                                 ESYS_TR_NONE,
                                 &primary_sensitive,
-                                primary_template,
+                                &primary_template,
                                 NULL,
                                 &creation_pcr,
                                 &primary->esys_handle,
@@ -634,7 +1086,12 @@ static int tpm2_make_primary(
         }
 
         if (IN_SET(alg, 0, TPM2_ALG_RSA)) {
-                primary_template = tpm2_get_primary_template(base_flags);
+                if (use_srk_model)
+                        r = tpm2_get_srk_template(c, TPM2_ALG_RSA, &primary_template.publicArea);
+                else
+                        r = tpm2_get_legacy_template(TPM2_ALG_RSA, &primary_template.publicArea);
+                if (r < 0)
+                        return r;
 
                 rc = sym_Esys_CreatePrimary(
                                 c->esys_context,
@@ -643,7 +1100,7 @@ static int tpm2_make_primary(
                                 ESYS_TR_NONE,
                                 ESYS_TR_NONE,
                                 &primary_sensitive,
-                                primary_template,
+                                &primary_template,
                                 NULL,
                                 &creation_pcr,
                                 &primary->esys_handle,
@@ -668,11 +1125,11 @@ static int tpm2_make_primary(
 
         if (use_srk_model) {
                 rc = sym_Esys_EvictControl(c->esys_context, ESYS_TR_RH_OWNER, primary->esys_handle,
-                                ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, SRK_HANDLE, &primary->esys_handle);
+                                ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_SRK_HANDLE, &primary->esys_handle);
                 if (rc != TSS2_RC_SUCCESS)
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                                "Failed to persist SRK within TPM: %s", sym_Tss2_RC_Decode(rc));
-                primary->keep = true;
+                primary->flush = false;
         }
 
         if (ret_primary)
@@ -1180,48 +1637,33 @@ static int tpm2_get_best_pcr_bank(
                 uint32_t pcr_mask,
                 TPMI_ALG_HASH *ret) {
 
-        _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
+        TPML_PCR_SELECTION pcrs;
         TPMI_ALG_HASH supported_hash = 0, hash_with_valid_pcr = 0;
-        TPMI_YES_NO more;
-        TSS2_RC rc;
         int r;
 
         assert(c);
+        assert(ret);
 
-        rc = sym_Esys_GetCapability(
-                        c->esys_context,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        TPM2_CAP_PCRS,
-                        0,
-                        1,
-                        &more,
-                        &pcap);
-        if (rc != TSS2_RC_SUCCESS)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
-                                       "Failed to determine TPM2 PCR bank capabilities: %s", sym_Tss2_RC_Decode(rc));
-
-        assert(pcap->capability == TPM2_CAP_PCRS);
-
-        for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
+        pcrs = tpm2_capability_pcrs(c);
+        FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &pcrs) {
+                TPMI_ALG_HASH hash = selection->hash;
                 int good;
 
                 /* For now we are only interested in the SHA1 and SHA256 banks */
-                if (!IN_SET(pcap->data.assignedPCR.pcrSelections[i].hash, TPM2_ALG_SHA256, TPM2_ALG_SHA1))
+                if (!IN_SET(hash, TPM2_ALG_SHA256, TPM2_ALG_SHA1))
                         continue;
 
-                r = tpm2_bank_has24(pcap->data.assignedPCR.pcrSelections + i);
+                r = tpm2_bank_has24(selection);
                 if (r < 0)
                         return r;
                 if (!r)
                         continue;
 
-                good = tpm2_pcr_mask_good(c, pcap->data.assignedPCR.pcrSelections[i].hash, pcr_mask);
+                good = tpm2_pcr_mask_good(c, hash, pcr_mask);
                 if (good < 0)
                         return good;
 
-                if (pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA256) {
+                if (hash == TPM2_ALG_SHA256) {
                         supported_hash = TPM2_ALG_SHA256;
                         if (good) {
                                 /* Great, SHA256 is supported and has initialized PCR values, we are done. */
@@ -1229,7 +1671,7 @@ static int tpm2_get_best_pcr_bank(
                                 break;
                         }
                 } else {
-                        assert(pcap->data.assignedPCR.pcrSelections[i].hash == TPM2_ALG_SHA1);
+                        assert(hash == TPM2_ALG_SHA1);
 
                         if (supported_hash == 0)
                                 supported_hash = TPM2_ALG_SHA1;
@@ -1278,42 +1720,26 @@ int tpm2_get_good_pcr_banks(
                 TPMI_ALG_HASH **ret) {
 
         _cleanup_free_ TPMI_ALG_HASH *good_banks = NULL, *fallback_banks = NULL;
-        _cleanup_(Esys_Freep) TPMS_CAPABILITY_DATA *pcap = NULL;
+        TPML_PCR_SELECTION pcrs;
         size_t n_good_banks = 0, n_fallback_banks = 0;
-        TPMI_YES_NO more;
-        TSS2_RC rc;
         int r;
 
         assert(c);
         assert(ret);
 
-        rc = sym_Esys_GetCapability(
-                        c->esys_context,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        ESYS_TR_NONE,
-                        TPM2_CAP_PCRS,
-                        0,
-                        1,
-                        &more,
-                        &pcap);
-        if (rc != TSS2_RC_SUCCESS)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
-                                       "Failed to determine TPM2 PCR bank capabilities: %s", sym_Tss2_RC_Decode(rc));
-
-        assert(pcap->capability == TPM2_CAP_PCRS);
-
-        for (size_t i = 0; i < pcap->data.assignedPCR.count; i++) {
+        pcrs = tpm2_capability_pcrs(c);
+        FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &pcrs) {
+                TPMI_ALG_HASH hash = selection->hash;
 
                 /* Let's see if this bank is superficially OK, i.e. has at least 24 enabled registers */
-                r = tpm2_bank_has24(pcap->data.assignedPCR.pcrSelections + i);
+                r = tpm2_bank_has24(selection);
                 if (r < 0)
                         return r;
                 if (!r)
                         continue;
 
                 /* Let's now see if this bank has any of the selected PCRs actually initialized */
-                r = tpm2_pcr_mask_good(c, pcap->data.assignedPCR.pcrSelections[i].hash, pcr_mask);
+                r = tpm2_pcr_mask_good(c, hash, pcr_mask);
                 if (r < 0)
                         return r;
 
@@ -1324,12 +1750,12 @@ int tpm2_get_good_pcr_banks(
                         if (!GREEDY_REALLOC(good_banks, n_good_banks+1))
                                 return log_oom();
 
-                        good_banks[n_good_banks++] = pcap->data.assignedPCR.pcrSelections[i].hash;
+                        good_banks[n_good_banks++] = hash;
                 } else {
                         if (!GREEDY_REALLOC(fallback_banks, n_fallback_banks+1))
                                 return log_oom();
 
-                        fallback_banks[n_fallback_banks++] = pcap->data.assignedPCR.pcrSelections[i].hash;
+                        fallback_banks[n_fallback_banks++] = hash;
                 }
         }
 
@@ -1520,11 +1946,6 @@ static int tpm2_make_encryption_session(
                 const Tpm2Handle *bind_key,
                 Tpm2Handle **ret_session) {
 
-        static const TPMT_SYM_DEF symmetric = {
-                .algorithm = TPM2_ALG_AES,
-                .keyBits.aes = 128,
-                .mode.aes = TPM2_ALG_CFB,
-        };
         const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
                         TPMA_SESSION_CONTINUESESSION;
         TSS2_RC rc;
@@ -1538,7 +1959,7 @@ static int tpm2_make_encryption_session(
         /* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which
          * means that the random salt will be encrypted with the well-known key. That way, only the TPM can
          * recover the salt, which is then used for key derivation. */
-        _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
         r = tpm2_handle_new(c, &session);
         if (r < 0)
                 return r;
@@ -1552,7 +1973,7 @@ static int tpm2_make_encryption_session(
                         ESYS_TR_NONE,
                         NULL,
                         TPM2_SE_HMAC,
-                        &symmetric,
+                        &SESSION_TEMPLATE_SYM_AES_128_CFB,
                         TPM2_ALG_SHA256,
                         &session->esys_handle);
         if (rc != TSS2_RC_SUCCESS)
@@ -1581,11 +2002,6 @@ static int tpm2_make_policy_session(
                 bool trial,
                 Tpm2Handle **ret_session) {
 
-        static const TPMT_SYM_DEF symmetric = {
-                .algorithm = TPM2_ALG_AES,
-                .keyBits.aes = 128,
-                .mode.aes = TPM2_ALG_CFB,
-        };
         TPM2_SE session_type = trial ? TPM2_SE_TRIAL : TPM2_SE_POLICY;
         TSS2_RC rc;
         int r;
@@ -1601,7 +2017,7 @@ static int tpm2_make_policy_session(
 
         log_debug("Starting policy session.");
 
-        _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *session = NULL;
         r = tpm2_handle_new(c, &session);
         if (r < 0)
                 return r;
@@ -1615,7 +2031,7 @@ static int tpm2_make_policy_session(
                         ESYS_TR_NONE,
                         NULL,
                         session_type,
-                        &symmetric,
+                        &SESSION_TEMPLATE_SYM_AES_128_CFB,
                         TPM2_ALG_SHA256,
                         &session->esys_handle);
         if (rc != TSS2_RC_SUCCESS)
@@ -2162,7 +2578,7 @@ static int tpm2_policy_authorize(
 
         log_debug("Adding PCR signature policy.");
 
-        _cleanup_tpm2_handle_ Tpm2Handle *pubkey_handle = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *pubkey_handle = NULL;
         r = tpm2_handle_new(c, &pubkey_handle);
         if (r < 0)
                 return r;
@@ -2434,7 +2850,7 @@ int tpm2_seal(const char *device,
 
         CLEANUP_ERASE(hmac_sensitive);
 
-        _cleanup_tpm2_context_ Tpm2Context *c = NULL;
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
         r = tpm2_context_new(device, &c);
         if (r < 0)
                 return r;
@@ -2517,13 +2933,13 @@ int tpm2_seal(const char *device,
         if (r < 0)
                 return log_error_errno(r, "Failed to generate secret key: %m");
 
-        _cleanup_tpm2_handle_ Tpm2Handle *primary_handle = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
         TPMI_ALG_PUBLIC primary_alg;
         r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary_handle);
         if (r < 0)
                 return r;
 
-        _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
         r = tpm2_make_encryption_session(c, primary_handle, &TPM2_HANDLE_NONE, &encryption_session);
         if (r < 0)
                 return r;
@@ -2684,20 +3100,20 @@ int tpm2_unseal(const char *device,
                 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                        "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc));
 
-        _cleanup_tpm2_context_ Tpm2Context *c = NULL;
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
         r = tpm2_context_new(device, &c);
         if (r < 0)
                 return r;
 
         /* If their is a primary key we trust, like an SRK, use it */
-        _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *primary = NULL;
         if (srk_buf) {
 
                 r = tpm2_handle_new(c, &primary);
                 if (r < 0)
                         return r;
 
-                primary->keep = true;
+                primary->flush = false;
 
                 log_debug("Found existing SRK key to use, deserializing ESYS_TR");
                 rc = sym_Esys_TR_Deserialize(
@@ -2723,7 +3139,7 @@ int tpm2_unseal(const char *device,
          * SRK model, the tpmKey is verified. In the non-srk model, with pin, the bindKey
          * provides protections.
          */
-        _cleanup_tpm2_handle_ Tpm2Handle *hmac_key = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *hmac_key = NULL;
         r = tpm2_handle_new(c, &hmac_key);
         if (r < 0)
                 return r;
@@ -2772,13 +3188,13 @@ int tpm2_unseal(const char *device,
         if (r < 0)
                 return r;
 
-        _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
         r = tpm2_make_encryption_session(c, primary, hmac_key, &encryption_session);
         if (r < 0)
                 return r;
 
         for (unsigned i = RETRY_UNSEAL_MAX;; i--) {
-                _cleanup_tpm2_handle_ Tpm2Handle *policy_session = NULL;
+                _cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
                 _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
                 r = tpm2_make_policy_session(
                                 c,
index 964471098f58dd620ee088bc8f7167b35c234881..5fa64563796e8b28f938b440d68b53460c6f782c 100644 (file)
@@ -13,13 +13,6 @@ typedef enum TPM2Flags {
         TPM2_FLAGS_USE_PIN = 1 << 0,
 } TPM2Flags;
 
-
-typedef enum Tpm2SRKTemplateFlags {
-        TPM2_SRK_TEMPLATE_ECC       = 1 << 0,
-        TPM2_SRK_TEMPLATE_NEW_STYLE = 1 << 1,
-        _TPM2_SRK_TEMPLATE_MAX      = TPM2_SRK_TEMPLATE_NEW_STYLE|TPM2_SRK_TEMPLATE_ECC,
-} Tpm2SRKTemplateFlags;
-
 /* As per https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_v23_pub.pdf a
  * TPM2 on a Client PC must have at least 24 PCRs. This hardcodes our expectation of 24. */
 #define TPM2_PCRS_MAX 24U
@@ -67,18 +60,21 @@ typedef struct {
         void *tcti_dl;
         TSS2_TCTI_CONTEXT *tcti_context;
         ESYS_CONTEXT *esys_context;
+
+        /* Some selected cached capabilities of the TPM */
+        TPML_PCR_SELECTION capability_pcrs;
 } Tpm2Context;
 
 int tpm2_context_new(const char *device, Tpm2Context **ret_context);
 Tpm2Context *tpm2_context_ref(Tpm2Context *context);
 Tpm2Context *tpm2_context_unref(Tpm2Context *context);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Context*, tpm2_context_unref);
-#define _cleanup_tpm2_context_ _cleanup_(tpm2_context_unrefp)
 
 typedef struct {
         Tpm2Context *tpm2_context;
         ESYS_TR esys_handle;
-        bool keep;
+
+        bool flush;
 } Tpm2Handle;
 
 #define _tpm2_handle(c, h) { .tpm2_context = (c), .esys_handle = (h), }
@@ -87,7 +83,10 @@ static const Tpm2Handle TPM2_HANDLE_NONE = _tpm2_handle(NULL, ESYS_TR_NONE);
 int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle);
 Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free);
-#define _cleanup_tpm2_handle_ _cleanup_(tpm2_handle_freep)
+
+int tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg);
+
+bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARMS *parms);
 
 int tpm2_get_good_pcr_banks(Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret_banks);
 int tpm2_get_good_pcr_banks_strv(Tpm2Context *c, uint32_t pcr_mask, char ***ret);
@@ -113,8 +112,6 @@ char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l);
 size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l);
 #define tpm2_tpml_pcr_selection_is_empty(l) (tpm2_tpml_pcr_selection_weight(l) == 0)
 
-const TPM2B_PUBLIC *tpm2_get_primary_template(Tpm2SRKTemplateFlags flags);
-
 #else /* HAVE_TPM2 */
 typedef struct {} Tpm2Context;
 typedef struct {} Tpm2Handle;
index ab97af57e2fe09a11719a23f02791b900315b21d..333cd3af589dc657a3df1b8555d7ea8cda001e72 100644 (file)
@@ -2750,7 +2750,7 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t
                         return r;
         }
 
-        if (listen(fd, SOMAXCONN) < 0)
+        if (listen(fd, SOMAXCONN_DELUXE) < 0)
                 return -errno;
 
         r = varlink_server_create_listen_fd_socket(s, fd, &ss);
index 2d095f72df4cf269c27597423f64c91849776bcd..595b6f3374504ad19a6c0400711c681a0bbe7606 100644 (file)
@@ -298,7 +298,7 @@ int sd_pid_notifyf_with_fds(pid_t pid, int unset_environment, const int *fds, si
 /*
   Returns > 0 if synchronization with systemd succeeded.  Returns < 0
   on error. Returns 0 if $NOTIFY_SOCKET was not set. Note that the
-  timeout parameter of this function call takes the timeout in µs, and
+  timeout parameter of this function call takes the timeout in μs, and
   will be passed to ppoll(2), hence the behaviour will be similar to
   ppoll(2). This function can be called after sending a status message
   to systemd, if one needs to synchronize against reception of the
@@ -330,7 +330,7 @@ int sd_booted(void);
   Returns > 0 if the service manager expects watchdog keep-alive
   events to be sent regularly via sd_notify(0, "WATCHDOG=1"). Returns
   0 if it does not expect this. If the usec argument is non-NULL
-  returns the watchdog timeout in µs after which the service manager
+  returns the watchdog timeout in μs after which the service manager
   will act on a process that has not sent a watchdog keep alive
   message. This function is useful to implement services that
   recognize automatically if they are being run under supervision of
index 7246d9f472a5c83f826e1b5b7827735809ca6134..4700a76441a22d651c6361efdd4980eeff85cfa4 100644 (file)
@@ -184,6 +184,9 @@ int sd_session_get_desktop(const char *session, char **desktop);
 /* Determine the X11 display of this session. */
 int sd_session_get_display(const char *session, char **display);
 
+/* Determine the leader process of this session. */
+int sd_session_get_leader(const char *session, pid_t *leader);
+
 /* Determine the remote host of this session. */
 int sd_session_get_remote_host(const char *session, char **remote_host);
 
index fe1a0fec216594d30664ca452131511be9a83782..b57ba235394e2a9055f5bdbcf9158f3c23561f01 100644 (file)
@@ -200,16 +200,12 @@ tests += [
                 'condition' : 'HAVE_ACL',
         },
         {
-                'sources' : [
-                        files('test-af-list.c'),
-                        generated_gperf_headers,
-                ],
+                'sources' : files('test-af-list.c') +
+                            generated_gperf_headers,
         },
         {
-                'sources' : [
-                        files('test-arphrd-util.c'),
-                        generated_gperf_headers,
-                ],
+                'sources' : files('test-arphrd-util.c') +
+                            generated_gperf_headers,
         },
         {
                 'sources' : files('test-ask-password-api.c'),
@@ -228,10 +224,8 @@ tests += [
                 'type' : 'manual',
         },
         {
-                'sources' : [
-                        files('test-cap-list.c'),
-                        generated_gperf_headers,
-                ],
+                'sources' : files('test-cap-list.c') +
+                            generated_gperf_headers,
                 'dependencies' : libcap,
         },
         {
@@ -268,28 +262,25 @@ tests += [
                 'dependencies' : libp11kit_cflags
         },
         {
-                'sources' : [
-                        files('test-errno-list.c'),
-                        generated_gperf_headers,
-                ],
+                'sources' : files('test-errno-list.c') +
+                            generated_gperf_headers,
         },
         {
                 'sources' : files('test-fd-util.c'),
                 'dependencies' : libseccomp,
         },
         {
-                'sources' : [files(
-                        'test-hashmap.c',
-                        'test-hashmap-plain.c'),
-                        test_hashmap_ordered_c,
-                ],
+                'sources' : files(
+                                  'test-hashmap.c',
+                                  'test-hashmap-plain.c',
+                            ) + [
+                                   test_hashmap_ordered_c,
+                            ],
                 'timeout' : 180,
         },
         {
-                'sources' : [
-                        files('test-ip-protocol-list.c'),
-                        shared_generated_gperf_headers,
-                ],
+                'sources' : files('test-ip-protocol-list.c') +
+                            shared_generated_gperf_headers,
         },
         {
                 'sources' : files('test-ipcrm.c'),
index 67acba23a79d548791b8013eeec4d08cdb7bd231..ccb1661a9142eeeab43da6bbe664ae8917eed0a0 100644 (file)
@@ -54,11 +54,11 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to write file: %m");
 
-        r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", 0);
+        r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest2", 0);
         if (r < 0)
                 log_error_errno(r, "Failed to make snapshot: %m");
 
-        r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
+        r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
         if (r < 0)
                 log_error_errno(r, "Failed to make snapshot: %m");
 
@@ -74,7 +74,8 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
-        r = btrfs_subvol_snapshot("/etc", "/etc2", BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
+        r = btrfs_subvol_snapshot_at(AT_FDCWD, "/etc", AT_FDCWD, "/etc2",
+                                     BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
         if (r < 0)
                 log_error_errno(r, "Failed to make snapshot: %m");
 
@@ -115,7 +116,7 @@ int main(int argc, char *argv[]) {
         if (mkdir("/xxxrectest/mnt", 0755) < 0)
                 log_error_errno(errno, "Failed to make directory: %m");
 
-        r = btrfs_subvol_snapshot("/xxxrectest", "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
+        r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxrectest", AT_FDCWD, "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
         if (r < 0)
                 log_error_errno(r, "Failed to snapshot subvolume: %m");
 
@@ -151,7 +152,8 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to set up quota limit: %m");
 
-        r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
+        r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxquotatest", AT_FDCWD, "/xxxquotatest2",
+                                     BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
         if (r < 0)
                 log_error_errno(r, "Failed to set up snapshot: %m");
 
index 558f4109e3f5395572b94886c7933f06dfe909f9..75c508970e1b511f7673ccc5f8c2b4136773c779 100644 (file)
 
 static const char *arg_test_dir = NULL;
 
+static void test_chase_extract_filename_one(const char *path, const char *root, const char *expected) {
+        _cleanup_free_ char *ret1 = NULL, *ret2 = NULL, *fname = NULL;
+
+        log_debug("/* %s(path=%s, root=%s) */", __func__, path, strnull(root));
+
+        assert_se(chase(path, root, CHASE_EXTRACT_FILENAME, &ret1, NULL) > 0);
+        assert_se(streq(ret1, expected));
+
+        assert_se(chase(path, root, 0, &ret2, NULL) > 0);
+        assert_se(chase_extract_filename(ret2, root, &fname) >= 0);
+        assert_se(streq(fname, expected));
+}
+
 TEST(chase) {
         _cleanup_free_ char *result = NULL, *pwd = NULL;
         _cleanup_close_ int pfd = -EBADF;
@@ -111,6 +124,19 @@ TEST(chase) {
         assert_se(path_equal(result, temp));
         result = mfree(result);
 
+        /* Tests for CHASE_EXTRACT_FILENAME and chase_extract_filename() */
+
+        p = strjoina(temp, "/start");
+        pslash = strjoina(p, "/");
+        test_chase_extract_filename_one(p, NULL, "usr");
+        test_chase_extract_filename_one(pslash, NULL, "usr");
+        test_chase_extract_filename_one(p, temp, "usr");
+        test_chase_extract_filename_one(pslash, temp, "usr");
+
+        p = strjoina(temp, "/slash");
+        test_chase_extract_filename_one(p, NULL, ".");
+        test_chase_extract_filename_one(p, temp, ".");
+
         /* Paths that would "escape" outside of the "root" */
 
         p = strjoina(temp, "/6dots");
@@ -548,7 +574,7 @@ TEST(chaseat) {
 
         assert_se(chaseat(tfd, "i/../p", CHASE_MKDIR_0755|CHASE_NONEXISTENT, NULL, NULL) == -ENOENT);
 
-        /* Test CHASE_FILENAME */
+        /* Test CHASE_EXTRACT_FILENAME */
 
         assert_se(chaseat(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_NOFOLLOW|CHASE_EXTRACT_FILENAME, &result, &fd) >= 0);
         assert_se(faccessat(fd, result, F_OK, AT_SYMLINK_NOFOLLOW) >= 0);
@@ -570,6 +596,10 @@ TEST(chaseat) {
         assert_se(streq(result, "."));
         result = mfree(result);
 
+        assert_se(chaseat(tfd, NULL, CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, NULL) >= 0);
+        assert_se(streq(result, "."));
+        result = mfree(result);
+
         /* Test chase_and_openat() */
 
         fd = chase_and_openat(tfd, "o/p/e/n/f/i/l/e", CHASE_MKDIR_0755, O_CREAT|O_EXCL|O_CLOEXEC, NULL);
@@ -582,6 +612,12 @@ TEST(chaseat) {
         assert_se(fd_verify_directory(fd) >= 0);
         fd = safe_close(fd);
 
+        fd = chase_and_openat(tfd, NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_PATH|O_DIRECTORY|O_CLOEXEC, &result);
+        assert_se(fd >= 0);
+        assert_se(streq(result, "."));
+        fd = safe_close(fd);
+        result = mfree(result);
+
         /* Test chase_and_openatdir() */
 
         assert_se(chase_and_opendirat(tfd, "o/p/e/n/d/i", 0, &result, &dir) >= 0);
@@ -643,11 +679,6 @@ TEST(chaseat) {
         result = mfree(result);
 }
 
-static int intro(void) {
-        arg_test_dir = saved_argv[1];
-        return EXIT_SUCCESS;
-}
-
 TEST(chaseat_prefix_root) {
         _cleanup_free_ char *cwd = NULL, *ret = NULL, *expected = NULL;
 
@@ -685,4 +716,9 @@ TEST(chaseat_prefix_root) {
         assert_se(streq(ret, expected));
 }
 
+static int intro(void) {
+        arg_test_dir = saved_argv[1];
+        return EXIT_SUCCESS;
+}
+
 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
index c8ec0e2278aa449d86c756d197e272cd5e623ba5..cc20031ed7ef23174f6d2c05c776c61e9266fd41 100644 (file)
@@ -22,7 +22,7 @@
         "e  \\\n"                               \
         "f  \n"                                 \
         "g=g\\ \n"                              \
-        "h= ąęół\\ śćńźżµ \n"                   \
+        "h= ąęół\\ śćńźżμ \n"                   \
         "i=i\\"
 
 #define env_file_2                              \
@@ -68,7 +68,7 @@ TEST(load_env_file_1) {
         assert_se(streq(data[1], "b=bc"));
         assert_se(streq(data[2], "d=de  f"));
         assert_se(streq(data[3], "g=g "));
-        assert_se(streq(data[4], "h=ąęół śćńźżµ"));
+        assert_se(streq(data[4], "h=ąęół śćńźżμ"));
         assert_se(streq(data[5], "i=i"));
         assert_se(data[6] == NULL);
 }
index a07c837e3f5c0b57e4f5f6e5cde70f4cd385f8d8..a63afa873b9170f434690a3c888d1662447310d2 100644 (file)
@@ -1299,7 +1299,7 @@ static int prepare_ns(const char *process_name) {
 
                 /* Copy unit files to make them accessible even when unprivileged. */
                 assert_se(get_testdata_dir("test-execute/", &unit_dir) >= 0);
-                assert_se(copy_directory(unit_dir, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
+                assert_se(copy_directory_at(AT_FDCWD, unit_dir, AT_FDCWD, PRIVATE_UNIT_DIR, COPY_MERGE_EMPTY) >= 0);
 
                 /* Prepare credstore like tmpfiles.d/credstore.conf for LoadCredential= tests. */
                 FOREACH_STRING(p, "/run/credstore", "/run/credstore.encrypted") {
index 80f762bc8966a28528d57f7a3486b8af04cf7884..4a39d06ef88a73501b7149598be20e58eab9e5a9 100644 (file)
@@ -214,7 +214,7 @@ TEST(benchmark_sd_id128_get_machine_app_specific) {
 
         q = now(CLOCK_MONOTONIC) - t;
 
-        log_info("%lf µs each\n", (double) q / iterations);
+        log_info("%lf μs each\n", (double) q / iterations);
 }
 
 TEST(id128_at) {
index 6b685a816f0bf06d17f152173084c1126df52d0b..31e2a3d296a570eee0ed03605557ca14f3adf509 100644 (file)
@@ -600,6 +600,17 @@ TEST(path_startswith) {
         test_path_startswith_one("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
         test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
 
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo", "/foo/./", "bar///barfoo/./.");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/", "/foo/./", "bar///barfoo/./.");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/", "/", "foo/./bar///barfoo/./.");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "////", "/",  "foo/./bar///barfoo/./.");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo//bar/////barfoo///", "/foo/./bar///barfoo/./.", "");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo////", "/foo/./bar///barfoo/./.", "");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar///barfoo/", "/foo/./bar///barfoo/./.", "");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo////bar/barfoo/", "/foo/./bar///barfoo/./.", "");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "////foo/bar/barfoo/", "/foo/./bar///barfoo/./.", "");
+        test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo", "/foo/./bar///barfoo/./.", "");
+
         test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
         test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
         test_path_startswith_one("/foo/bar/barfoo/", "", NULL, NULL);
index b90b8921926e3c15e06333454e8a8794c20caaeb..e915207e8c777d7fc3ef36ef3d103395d00a20d9 100644 (file)
@@ -614,7 +614,7 @@ TEST(getpid_measure) {
                 (void) getpid();
         q = now(CLOCK_MONOTONIC) - t;
 
-        log_info(" glibc getpid(): %lf µs each\n", (double) q / iterations);
+        log_info(" glibc getpid(): %lf μs each\n", (double) q / iterations);
 
         iterations *= 50; /* _cached() is about 50 times faster, so we need more iterations */
 
@@ -623,7 +623,7 @@ TEST(getpid_measure) {
                 (void) getpid_cached();
         q = now(CLOCK_MONOTONIC) - t;
 
-        log_info("getpid_cached(): %lf µs each\n", (double) q / iterations);
+        log_info("getpid_cached(): %lf μs each\n", (double) q / iterations);
 }
 
 TEST(safe_fork) {
index bcf2e843b0985102ac4e08f1940def4a6c946a8d..a297e9515edb5f6effb685c1b71d20faf8a27664 100644 (file)
@@ -124,10 +124,7 @@ TEST(serialize_strv) {
 
                 const char *t = startswith(line, "strv3=");
                 assert_se(t);
-
-                char *un;
-                assert_se(cunescape(t, 0, &un) >= 0);
-                assert_se(strv_consume(&strv2, un) >= 0);
+                assert_se(deserialize_strv(&strv2, t) >= 0);
         }
 
         assert_se(strv_equal(strv, strv2));
index 71ec766ca18d097a8d04f14e6df5b86cc23c1bcc..0259cbf3bb67c905c6565411d6b00e8ee0aeed13 100644 (file)
@@ -444,9 +444,9 @@ TEST(flush_accept) {
         assert_se(flush_accept(listen_dgram) < 0);
         assert_se(flush_accept(listen_seqpacket) < 0);
 
-        assert_se(listen(listen_stream, SOMAXCONN) >= 0);
-        assert_se(listen(listen_dgram, SOMAXCONN) < 0);
-        assert_se(listen(listen_seqpacket, SOMAXCONN) >= 0);
+        assert_se(listen(listen_stream, SOMAXCONN_DELUXE) >= 0);
+        assert_se(listen(listen_dgram, SOMAXCONN_DELUXE) < 0);
+        assert_se(listen(listen_seqpacket, SOMAXCONN_DELUXE) >= 0);
 
         assert_se(flush_accept(listen_stream) >= 0);
         assert_se(flush_accept(listen_dgram) < 0);
index 235c6cf164255de3d931d0b15a3901008a3a6132..a67bfc87342be4f1af7e231ac93364750f55fc55 100644 (file)
@@ -35,7 +35,9 @@ TEST(parse_sec) {
         assert_se(u == 700 * USEC_PER_MSEC);
         assert_se(parse_sec("23us", &u) >= 0);
         assert_se(u == 23);
-        assert_se(parse_sec("23µs", &u) >= 0);
+        assert_se(parse_sec("23μs", &u) >= 0); /* greek small letter mu */
+        assert_se(u == 23);
+        assert_se(parse_sec("23µs", &u) >= 0); /* micro symbol */
         assert_se(u == 23);
         assert_se(parse_sec("infinity", &u) >= 0);
         assert_se(u == USEC_INFINITY);
index 455b733422af8e5a20bdecdeebb6181f095be6d0..4859f62da8431cde9aba86a93e6d7a1ec16b7f24 100644 (file)
@@ -278,9 +278,9 @@ TEST(link_tmpfile) {
         assert_se(write(fd, "foobar\n", 7) == 7);
 
         assert_se(touch(d) >= 0);
-        assert_se(link_tmpfile(fd, tmp, d, /* replace= */ false) == -EEXIST);
+        assert_se(link_tmpfile(fd, tmp, d, /* flags= */ 0) == -EEXIST);
         assert_se(unlink(d) >= 0);
-        assert_se(link_tmpfile(fd, tmp, d, /* replace= */ false) >= 0);
+        assert_se(link_tmpfile(fd, tmp, d, /* flags= */ 0) >= 0);
 
         assert_se(read_one_line_file(d, &line) >= 0);
         assert_se(streq(line, "foobar"));
@@ -293,8 +293,8 @@ TEST(link_tmpfile) {
 
         assert_se(write(fd, "waumiau\n", 8) == 8);
 
-        assert_se(link_tmpfile(fd, tmp, d, /* replace= */ false) == -EEXIST);
-        assert_se(link_tmpfile(fd, tmp, d, /* replace= */ true) >= 0);
+        assert_se(link_tmpfile(fd, tmp, d, /* flags= */ 0) == -EEXIST);
+        assert_se(link_tmpfile(fd, tmp, d, LINK_TMPFILE_REPLACE) >= 0);
 
         line = mfree(line);
         assert_se(read_one_line_file(d, &line) >= 0);
index e878ab33f256b9b55a2daae75679ca6589266e52..f014c8f27e1ae94acf8eecde2e507c3ffc90c630 100644 (file)
@@ -458,96 +458,6 @@ TEST(tpml_pcr_selection_add_sub) {
                           expected2, expected2_count);
 }
 
-/* this test includes TPM2 specific data structures */
-TEST(tpm2_get_primary_template) {
-
-        /*
-         * Verify that if someone changes the template code, they know they're breaking things.
-         * Templates MUST be changed in a backwards compatible way.
-         *
-         */
-        static const TPM2B_PUBLIC templ[] = {
-                /* index 0 RSA old */
-                [0] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_RSA,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
-                                .parameters.rsaDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .keyBits = 2048,
-                                },
-                        },
-                },
-                /* Index 1 ECC old */
-                [TPM2_SRK_TEMPLATE_ECC] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_ECC,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
-                                .parameters.eccDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .curveID = TPM2_ECC_NIST_P256,
-                                        .kdf.scheme = TPM2_ALG_NULL,
-                                },
-                        },
-                },
-                /* index 2 RSA SRK */
-                [TPM2_SRK_TEMPLATE_NEW_STYLE] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_RSA,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_USERWITHAUTH|TPMA_OBJECT_NODA,
-                                .parameters.rsaDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .keyBits = 2048,
-                                },
-                        },
-                },
-                /* Index 3 ECC SRK */
-                [TPM2_SRK_TEMPLATE_NEW_STYLE | TPM2_SRK_TEMPLATE_ECC] = {
-                        .publicArea = {
-                                .type = TPM2_ALG_ECC,
-                                .nameAlg = TPM2_ALG_SHA256,
-                                .objectAttributes = TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_USERWITHAUTH|TPMA_OBJECT_NODA,
-                                .parameters.eccDetail = {
-                                        .symmetric = {
-                                                .algorithm = TPM2_ALG_AES,
-                                                .keyBits.aes = 128,
-                                                .mode.aes = TPM2_ALG_CFB,
-                                        },
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                        .curveID = TPM2_ECC_NIST_P256,
-                                        .kdf.scheme = TPM2_ALG_NULL,
-                                },
-                        },
-                },
-        };
-
-        assert_cc(ELEMENTSOF(templ) == _TPM2_SRK_TEMPLATE_MAX + 1);
-
-        for (size_t i = 0; i < ELEMENTSOF(templ); i++) {
-                /* the index counter lines up with the flags and the expected template received */
-                const TPM2B_PUBLIC *got = tpm2_get_primary_template((Tpm2SRKTemplateFlags)i);
-                assert_se(memcmp(&templ[i], got, sizeof(*got)) == 0);
-        }
-}
-
 static bool digest_check(const TPM2B_DIGEST *digest, const char *expect) {
         _cleanup_free_ char *h = NULL;
 
@@ -760,6 +670,44 @@ TEST(calculate_policy_pcr) {
         assert_se(digest_check(&d, "7481fd1b116078eb3ac2456e4ad542c9b46b9b8eb891335771ca8e7c8f8e4415"));
 }
 
+TEST(tpm_required_tests) {
+        int r;
+
+        _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
+        r = tpm2_context_new(NULL, &c);
+        if (r < 0) {
+                log_tests_skipped("Could not find TPM");
+                return;
+        }
+
+        TPMU_PUBLIC_PARMS parms = {
+                .symDetail.sym = {
+                        .algorithm = TPM2_ALG_AES,
+                        .keyBits.aes = 128,
+                        .mode.aes = TPM2_ALG_CFB,
+                },
+        };
+
+        /* Test with invalid parms */
+        assert_se(!tpm2_test_parms(c, TPM2_ALG_CFB, &parms));
+
+        TPMU_PUBLIC_PARMS invalid_parms = parms;
+        invalid_parms.symDetail.sym.keyBits.aes = 1;
+        assert_se(!tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &invalid_parms));
+
+        /* Test with valid parms */
+        assert_se(tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &parms));
+
+        /* Test invalid algs */
+        assert_se(tpm2_supports_alg(c, TPM2_ALG_ERROR) == 0);
+        assert_se(tpm2_supports_alg(c, TPM2_ALG_LAST + 1) == 0);
+
+        /* Test valid algs */
+        assert_se(tpm2_supports_alg(c, TPM2_ALG_RSA) == 1);
+        assert_se(tpm2_supports_alg(c, TPM2_ALG_AES) == 1);
+        assert_se(tpm2_supports_alg(c, TPM2_ALG_CFB) == 1);
+}
+
 #endif /* HAVE_TPM2 */
 
 DEFINE_TEST_MAIN(LOG_DEBUG);
index 569389b9d484f71fd2e537f98c60833ebcdb9e9e..07f66623a751d2fc939fcc355628ffe93713c81c 100644 (file)
@@ -622,7 +622,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                            "MESSAGE_ID=" SD_MESSAGE_TIME_SYNC_STR,
                            "MONOTONIC_USEC=" USEC_FMT, dts.monotonic,
                            "REALTIME_USEC=" USEC_FMT, dts.realtime,
-                           "BOOTIME_USEC=" USEC_FMT, dts.boottime);
+                           "BOOTTIME_USEC=" USEC_FMT, dts.boottime);
         }
 
         r = manager_arm_timer(m, m->poll_interval_usec);
index 416b536aed5079b3398707f38eca2f839518c3c4..1d8ebecc91d92dae036b4538e5b62fa8d16cd20b 100644 (file)
@@ -32,15 +32,15 @@ static int advance_tstamp(int fd, const struct stat *st) {
          * different timestamp accuracy: traditional fat has 2s granularity, and even ext2 and friends expose
          * different granularity depending on selected inode size during formatting! Hence, to ensure the
          * timestamp definitely is increased, here's what we'll do: we'll first try to increase the timestamp
-         * by 1µs, write that and read it back. If it was updated, great. But if it was not, we'll instead
-         * increase the timestamp by 10µs, and do the same, then 100µs, then 1ms, and so on, until it works,
+         * by 1μs, write that and read it back. If it was updated, great. But if it was not, we'll instead
+         * increase the timestamp by 10μs, and do the same, then 100μs, then 1ms, and so on, until it works,
          * or we reach 10s. If it still didn't work then, the fs is just broken and we give up. */
 
         usec_t target = MAX3(now(CLOCK_REALTIME),
                              TIME_EPOCH * USEC_PER_SEC,
                              timespec_load(&st->st_mtim));
 
-        for (usec_t a = 1; a <= 10 * USEC_PER_SEC; a *= 10) { /* 1µs, 10µs, 100µs, 1ms, … 10s */
+        for (usec_t a = 1; a <= 10 * USEC_PER_SEC; a *= 10) { /* 1μs, 10μs, 100μs, 1ms, … 10s */
                 struct timespec ts[2];
                 struct stat new_st;
 
index af1b904d329933219a6359b6023d4bb584a91fce..e0087d997b8b3d0886472b550088d60a4e9856ff 100644 (file)
@@ -1540,7 +1540,7 @@ static int fd_set_attribute(
                 return log_error_errno(procfs_fd, "Failed to re-open '%s': %m", path);
 
         unsigned previous, current;
-        r = chattr_full(NULL, procfs_fd, f, item->attribute_mask, &previous, &current, CHATTR_FALLBACK_BITWISE);
+        r = chattr_full(procfs_fd, NULL, f, item->attribute_mask, &previous, &current, CHATTR_FALLBACK_BITWISE);
         if (r == -ENOANO)
                 log_warning("Cannot set file attributes for '%s', maybe due to incompatibility in specified attributes, "
                             "previous=0x%08x, current=0x%08x, expected=0x%08x, ignoring.",
index 081948d223f59f92148c856c66a69ea4d2831a40..369db33fe4acb8bb0d99d420a43174aceadd9d1a 100644 (file)
@@ -154,12 +154,13 @@ if install_sysconfdir_samples
                      install_dir : sysconfdir / 'udev')
 endif
 
-custom_target(
+udev_pc = custom_target(
         'udev.pc',
         input : 'udev.pc.in',
         output : 'udev.pc',
         command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
         install : pkgconfigdatadir != 'no',
+        install_tag : 'devel',
         install_dir : pkgconfigdatadir)
 
 if install_sysconfdir
index 098e8ed0cc8a0f7c6e39a7009b0db819d01793be..7c0c2803d2a29cb17b322c05b2e4849a5170fb46 100644 (file)
@@ -392,10 +392,42 @@ static int stack_directory_open(sd_device *dev, const char *slink, int *ret_dirf
         return 0;
 }
 
+static int node_get_current(const char *slink, int dirfd, char **ret_id, int *ret_prio) {
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+        _cleanup_free_ char *id_dup = NULL;
+        const char *id;
+        int r;
+
+        assert(slink);
+        assert(dirfd >= 0);
+        assert(ret_id);
+
+        r = sd_device_new_from_devname(&dev, slink);
+        if (r < 0)
+                return r;
+
+        r = device_get_device_id(dev, &id);
+        if (r < 0)
+                return r;
+
+        id_dup = strdup(id);
+        if (!id_dup)
+                return -ENOMEM;
+
+        if (ret_prio) {
+                r = stack_directory_read_one(dirfd, id, NULL, ret_prio);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret_id = TAKE_PTR(id_dup);
+        return 0;
+}
+
 static int link_update(sd_device *dev, const char *slink, bool add) {
+        _cleanup_free_ char *current_id = NULL, *devnode = NULL;
         _cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
-        _cleanup_free_ char *devnode = NULL;
-        int r;
+        int r, current_prio;
 
         assert(dev);
         assert(slink);
@@ -404,10 +436,64 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
         if (r < 0)
                 return r;
 
+        r = node_get_current(slink, dirfd, &current_id, add ? &current_prio : NULL);
+        if (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))
+                return log_device_debug_errno(dev, r, "Failed to get the current device node priority for '%s': %m", slink);
+
         r = stack_directory_update(dev, dirfd, add);
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to update stack directory for '%s': %m", slink);
 
+        if (current_id) {
+                const char *id;
+
+                r = device_get_device_id(dev, &id);
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to get device id: %m");
+
+                if (add) {
+                        int prio;
+
+                        r = device_get_devlink_priority(dev, &prio);
+                        if (r < 0)
+                                return log_device_debug_errno(dev, r, "Failed to get devlink priority: %m");
+
+                        if (streq(current_id, id)) {
+                                if (current_prio <= prio)
+                                        /* The devlink is ours and already exists, and the new priority is
+                                         * equal or higher than the previous. Hence, it is not necessary to
+                                         * recreate it. */
+                                        return 0;
+
+                                /* The devlink priority is downgraded. Another device may have a higher
+                                 * priority now. Let's find the device node with the highest priority. */
+                        } else {
+                                if (current_prio >= prio)
+                                        /* The devlink with equal or higher priority already exists and is
+                                         * owned by another device. Hence, it is not necessary to recreate it. */
+                                        return 0;
+
+                                /* This device has a higher priority than the current. Let's create the
+                                 * devlink to our device node. */
+                                return node_symlink(dev, NULL, slink);
+                        }
+
+                } else {
+                        if (!streq(current_id, id))
+                                /* The devlink already exists and is owned by another device. Hence, it is
+                                 * not necessary to recreate it. */
+                                return 0;
+
+                        /* The current devlink is ours, and the target device will be removed. Hence, we need
+                         * to search the device that has the highest priority. and update the devlink. */
+                }
+        } else {
+                /* The requested devlink does not exist, or the target device does not exist and the devlink
+                 * points to a non-existing device. Let's search the deivce that has the highest priority,
+                 * and update the devlink. */
+                ;
+        }
+
         r = stack_directory_find_prioritized_devnode(dev, dirfd, add, &devnode);
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to determine device node with the highest priority for '%s': %m", slink);
index 8dc3a8d955a900ed8d6e8b8bb68884c1dc1cd39b..45a71b23f13ebaf0fbabe38f484d06bc3bdbbfb8 100644 (file)
@@ -142,7 +142,7 @@ int control_main(int argc, char *argv[], void *userdata) {
 
                         r = safe_atou(optarg, &i);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to parse maximum number of events '%s': %m", optarg);
+                                return log_error_errno(r, "Failed to parse maximum number of children '%s': %m", optarg);
 
                         r = udev_ctrl_send_set_children_max(uctrl, i);
                         if (r == -ENOANO)
index 80735b3fd9af9f9369c5ea17b5fc3e84b4173efa..8101ac52db23167cab7b8204e407d0e2f997b8d1 100644 (file)
@@ -272,7 +272,7 @@ int manager_startup(Manager *m) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to bind io.systemd.Multiplexer: %m");
 
-                if (listen(m->listen_fd, SOMAXCONN) < 0)
+                if (listen(m->listen_fd, SOMAXCONN_DELUXE) < 0)
                         return log_error_errno(errno, "Failed to listen on socket: %m");
         }
 
index f8466606ba3c4f2627eaaeae716ba15eaf6d0dd6..f3cf995ec2faea6739ff45e4f08ee804067bacd1 100644 (file)
@@ -639,7 +639,7 @@ int xdg_autostart_service_generate_unit(
                 "ExitType=cgroup\n"
                 "ExecStart=:%s\n"
                 "Restart=no\n"
-                "TimeoutSec=5s\n"
+                "TimeoutStopSec=5s\n"
                 "Slice=app.slice\n",
                 exec_start);
 
diff --git a/test/TEST-02-UNITTESTS/deny-list-ubuntu-ci-ppc64el b/test/TEST-02-UNITTESTS/deny-list-ubuntu-ci-ppc64el
deleted file mode 100644 (file)
index e69de29..0000000
index 3d766db3e744e4ec094e88b11e9dc9c7eca502b4..f165c993689b7ba7b075a6d4983987a1c8d9575f 100755 (executable)
@@ -2,6 +2,9 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 set -e
 
+# shellcheck source=test/test-functions
+. "${TEST_BASE_DIR:?}/test-functions"
+
 TEST_DESCRIPTION="Run unit tests under containers"
 RUN_IN_UNPRIVILEGED_CONTAINER=yes
 # Some tests make collecting coverage impossible (like test-mount-util, which
@@ -9,16 +12,23 @@ RUN_IN_UNPRIVILEGED_CONTAINER=yes
 # case
 IGNORE_MISSING_COVERAGE=yes
 
-# embed some newlines in the kernel command line to stress our test suite
+# Embed some newlines in the kernel command line to stress our test suite
+# Also, pass $TEST_PREFER_NSPAWN to the VM/container if set
+#
+# shellcheck disable=SC2015
 KERNEL_APPEND="
+$(get_bool "${TEST_PREFER_NSPAWN:-0}" && echo "systemd.setenv=TEST_PREFER_NSPAWN=1" || :)
 
 frobnicate!
 
+systemd.setenv=TEST_CMDLINE_NEWLINE=foo
+systemd.setenv=TEST_CMDLINE_NEWLINE=bar
+
 $KERNEL_APPEND
 "
-
-# shellcheck source=test/test-functions
-. "${TEST_BASE_DIR:?}/test-functions"
+# Override $TEST_PREFER_NSPAWN if it was set to always run both the QEMU and
+# the nspawn part of the test
+TEST_PREFER_NSPAWN=no
 
 test_append_files() {
     if get_bool "$LOOKS_LIKE_SUSE"; then
index 5d72638ec6f3de2fc63bcdca3f0d3b37c7a4d42d..340c74ef163bb5b60ca42cfa78894f4333df6cc8 100755 (executable)
@@ -42,16 +42,13 @@ test_append_files() {
     fi
 
     mkdir "$workspace/systemd-test-module"
-    cp systemd_test.te "$workspace/systemd-test-module"
-    cp systemd_test.if "$workspace/systemd-test-module"
-    cp systemd_test.fc "$workspace/systemd-test-module"
+    cp -v systemd_test.* "$workspace/systemd-test-module/"
+    image_install checkmodule load_policy m4 make sefcontext_compile semodule semodule_package runcon
     image_install -o sesearch
-    image_install runcon
-    image_install checkmodule semodule semodule_package m4 make load_policy sefcontext_compile
     image_install -o /usr/libexec/selinux/hll/pp # Fedora/RHEL/...
     image_install -o /usr/lib/selinux/hll/pp     # Debian/Ubuntu/...
 
-    if ! chroot "$workspace" make -C /systemd-test-module -f /usr/share/selinux/devel/Makefile clean systemd_test.pp; then
+    if ! chroot "$workspace" make -C /systemd-test-module -f /usr/share/selinux/devel/Makefile clean load systemd_test.pp QUIET=n; then
         dfatal "Failed to build the systemd test module"
         exit 1
     fi
index fd1b072c636b59fe85945a71c23c17ad32de9c45..4d480d753b6696fa58f54d40285e8f8b04ee4ef6 100755 (executable)
@@ -3,7 +3,6 @@
 set -e
 
 TEST_DESCRIPTION="EXTEND_TIMEOUT_USEC=usec start/runtime/stop tests"
-SKIP_INITRD=yes
 TEST_NO_QEMU=1
 
 # shellcheck source=test/test-functions
index eb0a6549e0ce228515e20bebb9833df392b6dbf8..4b1919b86ed4fe7002a861c3a9cc392bb20fb3fb 100755 (executable)
@@ -18,7 +18,7 @@ if ! get_bool "${TEST_PREFER_NSPAWN:=}"; then
     TEST_NO_NSPAWN=1
 fi
 
-command -v dfuzzer >/dev/null || exit 0
+test_require_bin dfuzzer
 
 if ! get_bool "$IS_BUILT_WITH_ASAN"; then
     echo "systemd is built without ASan, skipping..."
index 87ffaea453998d7795ba832ec72e4fa9719f7006..d0ec63d870874090b5aca41e15396cfa0e49a8c5 100755 (executable)
@@ -4,6 +4,7 @@ set -e
 
 TEST_DESCRIPTION="cryptsetup systemd setup"
 IMAGE_NAME="cryptsetup"
+IMAGE_ADDITIONAL_DATA_SIZE=100
 TEST_NO_NSPAWN=1
 TEST_FORCE_NEWIMAGE=1
 
@@ -12,28 +13,29 @@ TEST_FORCE_NEWIMAGE=1
 
 PART_UUID="deadbeef-dead-dead-beef-000000000000"
 DM_NAME="test24_varcrypt"
-KERNEL_APPEND+=" rd.luks=1 luks.name=$PART_UUID=$DM_NAME luks.key=$PART_UUID=/keyfile:LABEL=varcrypt_keydev"
+KERNEL_OPTIONS=(
+    "rd.luks=1"
+    "luks.name=$PART_UUID=$DM_NAME"
+    "luks.key=$PART_UUID=/keyfile:LABEL=varcrypt_keydev"
+    "luks.options=$PART_UUID=x-initrd.attach"
+)
+KERNEL_APPEND+=" ${KERNEL_OPTIONS[*]}"
 QEMU_OPTIONS+=" -drive format=raw,cache=unsafe,file=${STATEDIR:?}/keydev.img"
 
 check_result_qemu() {
-    local ret=1
+    local ret
 
     mount_initdir
-    [[ -e "${initdir:?}/testok" ]] && ret=0
-    [[ -f "$initdir/failed" ]] && cp -a "$initdir/failed" "${TESTDIR:?}"
 
     cryptsetup luksOpen "${LOOPDEV:?}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile"
     mount "/dev/mapper/$DM_NAME" "$initdir/var"
-    save_journal "$initdir/var/log/journal"
-    check_coverage_reports "${initdir:?}" || ret=5
+
+    check_result_common "${initdir:?}" && ret=0 || ret=$?
+
     _umount_dir "$initdir/var"
     _umount_dir "$initdir"
     cryptsetup luksClose "/dev/mapper/$DM_NAME"
 
-    [[ -f "$TESTDIR/failed" ]] && cat "$TESTDIR/failed"
-    echo "${JOURNAL_LIST:-No journals were saved}"
-
-    test -s "$TESTDIR/failed" && ret=1
     return $ret
 }
 
@@ -61,6 +63,7 @@ test_create_image() {
     mkdir -p "$STATEDIR/keydev"
     mount "$STATEDIR/keydev.img" "$STATEDIR/keydev"
     echo -n test >"$STATEDIR/keydev/keyfile"
+    sync "$STATEDIR/keydev"
     umount "$STATEDIR/keydev"
 
     cat >>"$initdir/etc/fstab" <<EOF
@@ -97,9 +100,9 @@ EOF
 }
 
 cleanup_root_var() {
-    ddebug "umount ${initdir:?}/var"
-    mountpoint "$initdir/var" && umount "$initdir/var"
+    mountpoint -q "$initdir/var" && umount "$initdir/var"
     [[ -b "/dev/mapper/${DM_NAME:?}" ]] && cryptsetup luksClose "/dev/mapper/$DM_NAME"
+    mountpoint -q "${STATEDIR:?}/keydev" && umount "$STATEDIR/keydev"
 }
 
 test_cleanup() {
index 844c08ab1f2b78846cda6307ec99ebe340ea0644..1d1dab43c30604b50dd1183450d22ce3479b913d 100755 (executable)
@@ -9,7 +9,7 @@ IMAGE_NAME="private-users"
 . "${TEST_BASE_DIR:?}/test-functions"
 
 has_user_dbus_socket || exit 0
-command -v mksquashfs >/dev/null 2>&1 || exit 0
+test_require_bin mksquashfs
 
 test_append_files() {
     inst_binary unsquashfs
index 0daf211103cbff952b02d8eb7c972772d8e905f7..3bf3891380ca28c61a7898747da4109d8d09c67a 100755 (executable)
@@ -11,10 +11,7 @@ TEST_DESCRIPTION="testing homed"
 . "${TEST_BASE_DIR:?}/test-functions"
 
 get_bool "${NO_BUILD:-}" && HOMECTL_BIN="homectl" || HOMECTL_BIN="${BUILD_DIR:?}/homectl"
-if ! command -v "$HOMECTL_BIN" >/dev/null; then
-    echo "Built without systemd-homed, skipping the test"
-    exit 0
-fi
+test_require_bin "$HOMECTL_BIN"
 
 # Need loop devices for mounting images
 test_append_files() {
index 2d44ca2b6ee21ccc91fe3446ac6b8bf7db05c89d..bcc81749afca6768644e541018b4870451afee2c 100755 (executable)
@@ -12,9 +12,7 @@ TEST_INSTALL_VERITY_MINIMAL=1
 # shellcheck source=test/test-functions
 . "${TEST_BASE_DIR:?}/test-functions"
 
-command -v mksquashfs >/dev/null 2>&1 || exit 0
-command -v veritysetup >/dev/null 2>&1 || exit 0
-command -v sfdisk >/dev/null 2>&1 || exit 0
+test_require_bin mksquashfs veritysetup sfdisk
 
 test_append_files() {
     instmods squashfs =squashfs
index 7549de568c2d7a16dfb36c575a652ef76479037c..d6e6ac0b226d77d7a9d3621e2f80b4c6eb898a35 100755 (executable)
@@ -4,6 +4,7 @@ set -e
 
 TEST_DESCRIPTION="test systemd-repart"
 IMAGE_NAME="repart"
+IMAGE_ADDITIONAL_ROOT_SIZE=1000
 TEST_FORCE_NEWIMAGE=1
 
 # shellcheck source=test/test-functions
diff --git a/test/TEST-61-UNITTESTS-QEMU/Makefile b/test/TEST-61-UNITTESTS-QEMU/Makefile
deleted file mode 120000 (symlink)
index e9f93b1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-61-UNITTESTS-QEMU/deny-list-ubuntu-ci b/test/TEST-61-UNITTESTS-QEMU/deny-list-ubuntu-ci
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/test/TEST-61-UNITTESTS-QEMU/test.sh b/test/TEST-61-UNITTESTS-QEMU/test.sh
deleted file mode 100755 (executable)
index 45c5f71..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-set -e
-
-TEST_DESCRIPTION="Run unit tests under qemu"
-# this subset of unit tests requires qemu, so they are ran here to avoid slowing down TEST-02
-TEST_NO_NSPAWN=1
-
-# embed some newlines in the kernel command line to stress our test suite
-KERNEL_APPEND="
-
-frobnicate!
-
-$KERNEL_APPEND
-"
-
-# shellcheck source=test/test-functions
-. "${TEST_BASE_DIR:?}/test-functions"
-
-check_result_nspawn() {
-    check_result_nspawn_unittests "${1}"
-}
-
-check_result_qemu() {
-    check_result_qemu_unittests
-}
-
-do_test "$@"
index f448a4a5f1008615100e76befddf7bcc3a88ab04..f3ac1399fce2a0d66142e8f35fb6cd54fae7a0fe 100755 (executable)
@@ -5,41 +5,23 @@ set -e
 TEST_DESCRIPTION="cryptenroll/cryptsetup with TPM2 devices"
 IMAGE_NAME="tpm2"
 TEST_NO_NSPAWN=1
+TEST_SETUP_SWTPM=1
 TEST_REQUIRE_INSTALL_TESTS=0
 
 # shellcheck source=test/test-functions
 . "${TEST_BASE_DIR:?}/test-functions"
 
-command -v swtpm >/dev/null 2>&1 || exit 0
-command -v tpm2_pcrextend >/dev/null 2>&1 || exit 0
+test_require_bin swtpm tpm2_pcrextend
 
 test_append_files() {
-        local workspace="${1:?}"
-
-        instmods tpm tpm_tis tpm_ibmvtpm
-        install_dmevent
-        generate_module_dependencies
-        inst_binary tpm2_pcrextend
-        inst_binary tpm2_pcrread
-        inst_binary openssl
+    local workspace="${1:?}"
+
+    instmods tpm tpm_tis tpm_ibmvtpm
+    install_dmevent
+    generate_module_dependencies
+    inst_binary tpm2_pcrextend
+    inst_binary tpm2_pcrread
+    inst_binary openssl
 }
 
-TEST_70_TPM_DEVICE="tpm-tis"
-if [[ "$(uname -m)" == "ppc64le" ]]; then
-    # tpm-spapr support was introduced in qemu 5.0.0. Skip test for old qemu versions.
-    qemu_min_version "5.0.0" || exit 0
-    TEST_70_TPM_DEVICE="tpm-spapr"
-fi
-
-TEST_70_at_exit() {
-    [[ -n "${TEST_70_SWTPM_PID:-}" ]] && kill "$TEST_70_SWTPM_PID" &>/dev/null
-    [[ -n "${TEST_70_TPM_STATE:-}" ]] && rm -rf "$TEST_70_TPM_STATE"
-}
-
-TEST_70_TPM_STATE="$(mktemp -d)"
-swtpm socket --tpm2 --tpmstate dir="$TEST_70_TPM_STATE" --ctrl type=unixio,path="$TEST_70_TPM_STATE/sock" &
-TEST_70_SWTPM_PID=$!
-add_at_exit_handler TEST_70_at_exit
-QEMU_OPTIONS+=" -chardev socket,id=chrtpm,path=$TEST_70_TPM_STATE/sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device $TEST_70_TPM_DEVICE,tpmdev=tpm0"
-
 do_test "$@"
index 6c63db65fb371d213fe3c6f2fc806a4a0e01e3b4..cbb9e3dbbf7aa7b0edee504c726617d5a00e714b 100755 (executable)
@@ -9,10 +9,7 @@ NSPAWN_ARGUMENTS="--private-network"
 # shellcheck source=test/test-functions
 . "${TEST_BASE_DIR:?}/test-functions"
 
-if ! command -v knotd >/dev/null; then
-    echo "This test requires Knot DNS server, skipping..."
-    exit 0
-fi
+test_require_bin knotd
 
 # We need at least Knot 3.0 which support (among others) the ds-push directive
 if ! knotc -c "${TEST_BASE_DIR:?}/knot-data/knot.conf" conf-check; then
index 3efbad21b6f1f91eae40c0f6d1759523ce8743cc..432a49fa1b4d3bd1ded55ddfc637ffef186bc50f 100755 (executable)
@@ -28,11 +28,11 @@ cp -a "$ROOTDIR/hwdb.d" "$D/etc/udev/hwdb.d"
 err=$("$SYSTEMD_HWDB" update --root "$D" 2>&1 >/dev/null) && rc= || rc=$?
 if [ -n "$err" ]; then
     echo "$err"
-    exit ${rc:-1}
+    exit "${rc:-1}"
 fi
 if [ -n "$rc" ]; then
     echo "$SYSTEMD_HWDB returned $rc"
-    exit $rc
+    exit "$rc"
 fi
 
 if [ ! -e "$D/etc/udev/hwdb.bin" ]; then
@@ -47,7 +47,7 @@ cp -a "$ROOTDIR/test/hwdb.d" "$D/etc/udev/hwdb.d"
 err=$("$SYSTEMD_HWDB" update --root "$D" 2>&1 >/dev/null) && rc= || rc=$?
 if [ -n "$rc" ]; then
     echo "$SYSTEMD_HWDB returned $rc"
-    exit $rc
+    exit "$rc"
 fi
 if [ -n "$err" ]; then
     echo "Expected warnings"
index b7e36f529e6b9bab1bc0e8cca3c17d2309874f4c..734fa209affe55bb34b747e62a0ff5b1ad0f7685 100644 (file)
@@ -11,9 +11,11 @@ ExecStart=test -w %S/aaa/ccc
 ExecStart=test -w %S/xxx
 ExecStart=test -w %S/xxx/yyy
 ExecStart=test -w %S/xxx/zzz
+ExecStart=test -w %S/abc
 ExecStart=test -w %S/aaa/111
 ExecStart=test -w %S/aaa/222
 ExecStart=test -w %S/aaa/333
+ExecStart=test -w %S/d:ef
 
 ExecStart=test -d %S/waldo
 ExecStart=test -d %S/quux/pief
@@ -23,9 +25,11 @@ ExecStart=test -d %S/aaa/ccc
 ExecStart=test -d %S/xxx
 ExecStart=test -d %S/xxx/yyy
 ExecStart=test -d %S/xxx/zzz
+ExecStart=test -d %S/abc
 ExecStart=test -L %S/aaa/111
 ExecStart=test -L %S/aaa/222
 ExecStart=test -L %S/aaa/333
+ExecStart=test -L %S/d:ef
 
 ExecStart=touch %S/waldo/hoge
 ExecStart=touch %S/quux/pief/hoge
@@ -35,9 +39,11 @@ ExecStart=touch %S/aaa/ccc/hoge
 ExecStart=touch %S/xxx/hoge
 ExecStart=touch %S/xxx/yyy/hoge
 ExecStart=touch %S/xxx/zzz/hoge
+ExecStart=touch %S/abc/hoge
 ExecStart=touch %S/aaa/111/foo
 ExecStart=touch %S/aaa/222/foo
 ExecStart=touch %S/aaa/333/foo
+ExecStart=touch %S/d:ef/foo
 
 ExecStart=test -f %S/waldo/hoge
 ExecStart=test -f %S/quux/pief/hoge
@@ -47,12 +53,14 @@ ExecStart=test -f %S/aaa/ccc/hoge
 ExecStart=test -f %S/xxx/hoge
 ExecStart=test -f %S/xxx/yyy/hoge
 ExecStart=test -f %S/xxx/zzz/hoge
+ExecStart=test -f %S/abc/hoge
 ExecStart=test -f %S/aaa/111/foo
 ExecStart=test -f %S/aaa/222/foo
 ExecStart=test -f %S/aaa/333/foo
 ExecStart=test -f %S/xxx/foo
 ExecStart=test -f %S/xxx/yyy/foo
 ExecStart=test -f %S/xxx/zzz/foo
+ExecStart=test -f %S/d:ef/foo
 
 ExecStart=test -f %S/private/waldo/hoge
 ExecStart=test -f %S/private/quux/pief/hoge
@@ -62,6 +70,7 @@ ExecStart=test -f %S/private/aaa/ccc/hoge
 ExecStart=test -f %S/private/xxx/hoge
 ExecStart=test -f %S/private/xxx/yyy/hoge
 ExecStart=test -f %S/private/xxx/zzz/hoge
+ExecStart=test -f %S/private/abc/hoge
 ExecStart=test -f %S/private/aaa/111/foo
 ExecStart=test -f %S/private/aaa/222/foo
 ExecStart=test -f %S/private/aaa/333/foo
@@ -69,8 +78,8 @@ ExecStart=test -f %S/private/xxx/foo
 ExecStart=test -f %S/private/xxx/yyy/foo
 ExecStart=test -f %S/private/xxx/zzz/foo
 
-ExecStart=sh -x -c 'test "$$STATE_DIRECTORY" = "%S/aaa:%S/aaa/bbb:%S/aaa/ccc:%S/quux/pief:%S/waldo:%S/xxx:%S/xxx/yyy:%S/xxx/zzz"'
+ExecStart=sh -x -c 'test "$$STATE_DIRECTORY" = "%S/aaa:%S/aaa/bbb:%S/aaa/ccc:%S/abc:%S/quux/pief:%S/waldo:%S/xxx:%S/xxx/yyy:%S/xxx/zzz"'
 
 Type=oneshot
 DynamicUser=yes
-StateDirectory=waldo quux/pief aaa/bbb aaa aaa/ccc xxx/yyy:aaa/111 xxx:aaa/222 xxx/zzz:aaa/333
+StateDirectory=waldo quux/pief aaa/bbb aaa aaa/ccc xxx/yyy:aaa/111 xxx:aaa/222 xxx/zzz:aaa/333 abc:d\:ef
index 95d943b87a04d5b746abd82c7bb832db0a5d4c66..147348899d1f15b0193fd120be91083fa8ef0b67 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/sdx1
-TimeoutSec=0
+TimeoutSec=infinity
index d6c59ff6089c383fe9f884938023e6f083a1716f..85c1936bce1420e9c344b4c7987c89c5f1b2960c 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/disk/by-label/Root
-TimeoutSec=0
+TimeoutSec=infinity
index cd9583c4dd01513667ec7c122543933053822e6d..1c7eaea10352249a84808f94d174556d27369328 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/disk/by-uuid/3f5ad593-4546-4a94-a374-bcfb68aa11f7
-TimeoutSec=0
+TimeoutSec=infinity
index 650ed8070a6a6b5ffe891de7f847357ef5313466..ab27bfd79cca9b9c9881eb286b159cf35999d94b 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/disk/by-partuuid/3f5ad593-4546-4a94-a374-bcfb68aa11f7
-TimeoutSec=0
+TimeoutSec=infinity
index 95d943b87a04d5b746abd82c7bb832db0a5d4c66..147348899d1f15b0193fd120be91083fa8ef0b67 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/sdx1
-TimeoutSec=0
+TimeoutSec=infinity
index 95d943b87a04d5b746abd82c7bb832db0a5d4c66..147348899d1f15b0193fd120be91083fa8ef0b67 100644 (file)
@@ -14,4 +14,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-fsck /dev/sdx1
-TimeoutSec=0
+TimeoutSec=infinity
index 303c1ee680efadc2952a2aca7ff3a23cffcfd99c..4670c23e27d09163a686e522561a13959697f8ea 100644 (file)
@@ -15,4 +15,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-makefs ext4 /dev/sdx12
-TimeoutSec=0
+TimeoutSec=infinity
index 0911f03f62347cc3999ea67811615a4cd53a3e42..0b0e7270bab6e54e03616919b88042d4c0bf4d8c 100644 (file)
@@ -15,4 +15,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-makefs swap /dev/sdy2
-TimeoutSec=0
+TimeoutSec=infinity
index 6201fec86be690f9e334304a81b4d222e71d710e..1164c99476c7e2296e872c6e590a48a7fd3f7fa1 100644 (file)
@@ -15,4 +15,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/usr/lib/systemd/systemd-makefs swap /dev/sdy3
-TimeoutSec=0
+TimeoutSec=infinity
index 4df6184d0096b8e6ef32f5c86ff1d8f515f193c4..0c20e60ad3d29724076d2f8f9896bbaec044f178 100644 (file)
@@ -69,21 +69,14 @@ _at_exit() {
     # Run the EXIT handlers in reverse order
     for ((i = ${#_AT_EXIT_HANDLERS[@]} - 1; i >= 0; i--)); do
         ddebug "Running EXIT handler '${_AT_EXIT_HANDLERS[$i]}'"
-        "${_AT_EXIT_HANDLERS[$i]}"
+        eval "${_AT_EXIT_HANDLERS[$i]}"
     done
 }
 
 trap _at_exit EXIT
 
 add_at_exit_handler() {
-    local handler="${1?}"
-
-    if [[ "$(type -t "$handler")" != "function" ]]; then
-        dfatal "'$handler' is not a function"
-        exit 1
-    fi
-
-    _AT_EXIT_HANDLERS+=("$handler")
+    _AT_EXIT_HANDLERS+=("${1:?}")
 }
 
 # Decide if we can (and want to) run qemu with KVM acceleration.
@@ -302,7 +295,6 @@ IS_BUILT_WITH_COVERAGE=$(is_built_with_coverage && echo yes || echo no)
 
 if get_bool "$IS_BUILT_WITH_ASAN"; then
     PATH_TO_INIT="$ROOTLIBDIR/systemd-under-asan"
-    SKIP_INITRD="${SKIP_INITRD:-yes}"
     QEMU_MEM="${QEMU_MEM:-2G}"
     QEMU_SMP="${QEMU_SMP:-4}"
 
@@ -333,6 +325,17 @@ if get_bool "$IS_BUILT_WITH_ASAN"; then
     echo "Detected ASan RT '$ASAN_RT_NAME' located at '$ASAN_RT_PATH'"
 fi
 
+test_require_bin() {
+    local bin
+
+    for bin in "$@"; do
+        if ! command -v "$bin" >/dev/null; then
+            echo "Required binary $bin not available, skipping the test"
+            exit 0
+        fi
+    done
+}
+
 find_qemu_bin() {
     QEMU_BIN="${QEMU_BIN:-""}"
     # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
@@ -364,6 +367,48 @@ find_qemu_bin() {
     fi
 }
 
+qemu_setup_swtpm_socket() {
+    local pid state_dir tpm_device
+
+    if ! tpm_device="$(qemu_get_tpm_device)"; then
+        dinfo "Found QEMU version is too old for TPM2 on ppc64le"
+        exit 0
+    fi
+
+    state_dir="$(mktemp -d)"
+    swtpm socket --tpm2 --tpmstate dir="$state_dir" --ctrl type=unixio,path="$state_dir/sock" &
+    pid=$!
+    if ! kill -0 "$pid"; then
+        echo >&2 "Failed to setup swtpm socket"
+        return 1
+    fi
+
+    dinfo "Started swtpm as PID $pid with state dir $state_dir"
+
+    add_at_exit_handler "kill -TERM $pid 2>/dev/null; rm -rf '$state_dir'"
+
+    QEMU_OPTIONS+=" -chardev socket,id=chrtpm,path=$state_dir/sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device $tpm_device,tpmdev=tpm0"
+    dinfo "Configured emulated TPM2 device $tpm_device"
+
+    return 0
+}
+
+qemu_get_tpm_device() {
+    local tpm_device="tpm-tis"
+
+    if [[ "$(uname -m)" == "ppc64le" ]]; then
+        # tpm-spapr support was introduced in qemu 5.0.0
+        if ! qemu_min_version "5.0.0"; then
+            return 1
+        fi
+
+        tpm_device="tpm-spapr"
+    fi
+
+    echo "$tpm_device"
+    return 0
+}
+
 # Compares argument #1=X.Y.Z (X&Y&Z = numeric) to the version of the installed qemu
 # returns 0 if newer or equal
 # returns 1 if older
@@ -454,6 +499,10 @@ run_qemu() {
 
     find_qemu_bin || return 1
 
+    if get_bool "${TEST_SETUP_SWTPM:-}"; then
+        qemu_setup_swtpm_socket || return 1
+    fi
+
     # Umount initdir to avoid concurrent access to the filesystem
     _umount_dir "$initdir"
 
@@ -527,7 +576,7 @@ run_qemu() {
         kernel_params+=("${user_kernel_append[@]}")
     fi
 
-    if [[ "$INITRD" ]] && ! get_bool "$SKIP_INITRD"; then
+    if [[ -n "$INITRD" ]]; then
         qemu_options+=(-initrd "$INITRD")
     fi
 
@@ -802,7 +851,7 @@ setup_selinux() {
     fi
 
     local conf_dir=/etc/selinux
-    local fixfiles_tools=(bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles)
+    local fixfiles_tools=(awk bash cat chcon expr egrep find grep head secon setfiles rm sort uname uniq)
 
     # Make sure the following statement can't expand to "/" to prevent
     # a potential where-are-my-backups situation
@@ -812,6 +861,16 @@ setup_selinux() {
         exit 1
     fi
 
+    # We use a custom autorelabel service instead of the SELinux provided set
+    # of units & a generator, since the generator overrides the default target
+    # to the SELinux one when it detects /.autorelabel. However, we use
+    # systemd.unit= on the kernel command cmdline which always takes precedence,
+    # rendering all SELinux efforts useless. Also, pulling in selinux-autorelabel.service
+    # explicitly doesn't work either, as it doesn't check for the presence of /.autorelabel
+    # and does the relabeling unconditionally which always ends with a reboot, so
+    # we end up in a reboot loop (and it also spews quite a lot of errors as it
+    # wants /etc/fstab and dracut-initramfs-restore).
+
     touch "$initdir/.autorelabel"
     mkdir -p "$initdir/usr/lib/systemd/tests/testdata/units/basic.target.wants"
     ln -sf ../autorelabel.service "$initdir/usr/lib/systemd/tests/testdata/units/basic.target.wants/"
@@ -871,6 +930,7 @@ create_asan_wrapper() {
         # runtime ASan DSO is in a non-standard (library) path.
         mkdir -p "${initdir:?}/etc/ld.so.conf.d/"
         echo "${ASAN_RT_PATH%/*}" >"${initdir:?}/etc/ld.so.conf.d/asan-path-override.conf"
+        ldconfig -r "$initdir"
     fi
 
     # Create a simple environment file which can be included by systemd services
@@ -1373,7 +1433,7 @@ cleanup_loopdev() {
 add_at_exit_handler cleanup_loopdev
 
 create_empty_image() {
-    if [ -z "${IMAGE_NAME:=}" ]; then
+    if [[ -z "${IMAGE_NAME:=}" ]]; then
         echo "create_empty_image: \$IMAGE_NAME not set"
         exit 1
     fi
@@ -1383,21 +1443,24 @@ create_empty_image() {
     local data_size=100
     if ! get_bool "$NO_BUILD"; then
         if meson configure "${BUILD_DIR:?}" | grep 'static-lib\|standalone-binaries' | awk '{ print $2 }' | grep -q 'true'; then
-            root_size=$((root_size+=200))
+            root_size=$((root_size + 200))
         fi
         if meson configure "${BUILD_DIR:?}" | grep 'link-.*-shared' | awk '{ print $2 }' | grep -q 'false'; then
-            root_size=$((root_size+=200))
+            root_size=$((root_size + 200))
         fi
         if get_bool "$IS_BUILT_WITH_COVERAGE"; then
-            root_size=$((root_size+=250))
+            root_size=$((root_size + 250))
         fi
         if get_bool "$IS_BUILT_WITH_ASAN"; then
             root_size=$((root_size * 2))
         fi
     fi
 
-    if [ "$IMAGE_NAME" = "repart" ]; then
-        root_size=$((root_size+=1000))
+    if [[ "${IMAGE_ADDITIONAL_ROOT_SIZE:-0}" -gt 0 ]]; then
+        root_size=$((root_size + IMAGE_ADDITIONAL_ROOT_SIZE))
+    fi
+    if [[ "${IMAGE_ADDITIONAL_DATA_SIZE:-0}" -gt 0 ]]; then
+        data_size=$((data_size + IMAGE_ADDITIONAL_DATA_SIZE))
     fi
 
     echo "Setting up ${IMAGE_PUBLIC:?} (${root_size} MB)"
@@ -1406,8 +1469,8 @@ create_empty_image() {
     # Create the blank file to use as a root filesystem
     truncate -s "${root_size}M" "$IMAGE_PUBLIC"
 
-    LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC")
-    [ -b "$LOOPDEV" ] || return 1
+    LOOPDEV="$(losetup --show -P -f "$IMAGE_PUBLIC")"
+    [[ -b "$LOOPDEV" ]] || return 1
     # Create two partitions - a root one and a data one (utilized by some tests)
     sfdisk "$LOOPDEV" <<EOF
 label: gpt
@@ -1662,8 +1725,7 @@ check_result_nspawn() {
         fi
     fi
 
-    check_result_common "${workspace}"
-    ret=$?
+    check_result_common "${workspace}" && ret=0 || ret=$?
 
     _umount_dir "${initdir:?}"
 
@@ -1683,8 +1745,7 @@ check_result_qemu() {
         fi
     fi
 
-    check_result_common "${initdir:?}"
-    ret=$?
+    check_result_common "${initdir:?}" && ret=0 || ret=$?
 
     _umount_dir "${initdir:?}"
 
@@ -2529,7 +2590,7 @@ inst_simple() {
         inst "${src%/*}/.${src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
     fi
     ddebug "Installing $src"
-    cp --sparse=always -pfL "$src" "${initdir}/$target"
+    cp --sparse=always --force --dereference --preserve=all "$src" "${initdir}/$target"
 }
 
 # find symlinks linked to given library file
@@ -2672,7 +2733,7 @@ inst_binary() {
     #     nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux)
     # delv, dig - pull in nss_resolve if `resolve` is in nsswitch.conf
     # tar - called by machinectl in TEST-25
-    bin_rx='/(chown|delv|dig|getent|id|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setfacl|setpriv|stat|su|tar|useradd|userdel)$'
+    bin_rx='/(agetty|chown|delv|dig|getfacl|getent|id|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setfacl|setpriv|stat|su|tar|useradd|userdel)$'
     if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ $bin_rx ]]; then
         wrap_binary=1
     fi
index 3bcc87561fd5b1ac97d20aae798b5de95e55d48d..5d66c6776d2daa104df9bbcb285bd85caa43130b 100755 (executable)
@@ -140,7 +140,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
 
     # shellcheck disable=SC2050
     [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
-    compare "${f%.*}" "(with login.defs)" $bound
+    compare "${f%.*}" "(with login.defs)" "$bound"
 done
 
 rm -f "$TESTDIR"/etc/sysusers.d/* "$TESTDIR"/usr/lib/sysusers.d/*
@@ -156,7 +156,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
 
     # shellcheck disable=SC2050
     [ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
-    compare "${f%.*}" "(with login.defs symlinked)" $bound
+    compare "${f%.*}" "(with login.defs symlinked)" "$bound"
 done
 
 rm -f "$TESTDIR"/etc/sysusers.d/* "$TESTDIR"/usr/lib/sysusers.d/*
diff --git a/test/testsuite-06.units/load-systemd-test-module.service b/test/testsuite-06.units/load-systemd-test-module.service
deleted file mode 100644 (file)
index 2d15a62..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Unit]
-Description=Load systemd-test module
-DefaultDependencies=no
-Requires=local-fs.target
-Conflicts=shutdown.target
-After=local-fs.target
-Before=sysinit.target shutdown.target autorelabel.service
-ConditionSecurity=selinux
-
-[Service]
-ExecStart=sh -x -c 'echo 0 >/sys/fs/selinux/enforce && make -C /systemd-test-module -f /usr/share/selinux/devel/Makefile load'
-Type=oneshot
-TimeoutSec=0
-RemainAfterExit=yes
index 1da1002cde800864408a5c660b9d4e0c1e77d442..dd0df8161bfa60eaf21b438b6cb2e189e3a116be 100644 (file)
@@ -10,10 +10,11 @@ ConditionSecurity=selinux
 ConditionPathExists=|/.autorelabel
 
 [Service]
-ExecStart=sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
+ExecStart=sh -xec 'echo 0 >/sys/fs/selinux/enforce; fixfiles -f -F relabel; rm /.autorelabel; systemctl --force reboot'
 Type=oneshot
-TimeoutSec=0
+TimeoutSec=infinity
 RemainAfterExit=yes
+StandardOutput=journal+console
 
 [Install]
 WantedBy=basic.target
index d8aaacb913c40c3793598a7ac067b5865843829d..4c4479287ffb44592afdd4e07706243452e6fc19 100755 (executable)
@@ -3,14 +3,33 @@
 set -eux
 set -o pipefail
 
+if ! systemd-detect-virt -qc && [[ "${TEST_CMDLINE_NEWLINE:-}" != bar ]]; then
+    cat /proc/cmdline
+    echo >&2 "Expected TEST_CMDLINE_NEWLINE=bar from the kernel command line"
+    exit 1
+fi
+
+# If we're running with TEST_PREFER_NSPAWN=1 limit the set of tests we run
+# in QEMU to only those that can't run in a container to avoid running
+# the same tests again in a, most likely, very slow environment
+if ! systemd-detect-virt -qc && [[ "${TEST_PREFER_NSPAWN:-0}" -ne 0 ]]; then
+    TESTS_GLOB="test-loop-block"
+else
+    TESTS_GLOB=${TESTS_GLOB:-test-*}
+fi
+
 NPROC=$(nproc)
 MAX_QUEUE_SIZE=${NPROC:-2}
-TESTS_GLOB=${TESTS_GLOB:-test-*}
 mapfile -t TEST_LIST < <(find /usr/lib/systemd/tests/unit-tests/ -maxdepth 1 -type f -name "${TESTS_GLOB}")
 
-# reset state
+# Reset state
 rm -fv /failed-tests /skipped-tests /skipped
 
+if ! systemd-detect-virt -qc; then
+    # Make sure ping works for unprivileged users (for test-bpf-firewall)
+    sysctl net.ipv4.ping_group_range="0 2147483647"
+fi
+
 # Check & report test results
 # Arguments:
 #   $1: test path
index b91f93ca09c40f20ed72650a6f32552f75a64c4a..c4c1d87fed5f5dd807d46c17c883a80e88361ffc 100644 (file)
@@ -2,9 +2,6 @@
 [Unit]
 Description=TEST-06-SELINUX
 
-Requires=load-systemd-test-module.service
-After=load-systemd-test-module.service
-
 [Service]
 ExecStartPre=rm -f /failed /testok
 ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
index ccae834371def7228ffe7bed53cb2c75359cc589..e192d1ccadbec5f550378bc11b665517f18652ec 100644 (file)
@@ -5,5 +5,5 @@ After=multi-user.target
 
 [Service]
 ExecStartPre=rm -f /failed /testok
-ExecStart=sh -x -e -c 'mountpoint /var; systemctl --state=failed --no-legend --no-pager >/failed; echo OK >/testok'
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
 Type=oneshot
diff --git a/test/units/testsuite-24.sh b/test/units/testsuite-24.sh
new file mode 100755 (executable)
index 0000000..391dcf9
--- /dev/null
@@ -0,0 +1,216 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+# TODO:
+#   - /proc/cmdline parsing
+#   - figure out token support (apart from TPM2, as that's covered by TEST-70-TPM2)
+#       - this might help https://www.qemu.org/docs/master/system/devices/ccid.html
+#   - expect + interactive auth?
+
+# We set up an encrypted /var partition which should get mounted automatically
+# on boot
+mountpoint /var
+
+systemctl --state=failed --no-legend --no-pager | tee /failed
+if [[ -s /failed ]]; then
+    echo >&2 "Found units in failed state"
+    exit 1
+fi
+
+at_exit() {
+    set +e
+
+    mountpoint -q /proc/cmdline && umount /proc/cmdline
+    rm -f /etc/crypttab
+    [[ -e /tmp/crypttab.bak ]] && cp -fv /tmp/crypttab.bak /etc/crypttab
+    [[ -n "${STORE_LOOP:-}" ]] && losetup -d "$STORE_LOOP"
+    [[ -n "${WORKDIR:-}" ]] && rm -rf "$WORKDIR"
+
+    systemctl daemon-reload
+}
+
+trap at_exit EXIT
+
+cryptsetup_start_and_check() {
+    local expect_fail=0
+    local ec volume unit
+
+    if [[ "${1:?}" == "-f" ]]; then
+        expect_fail=1
+        shift
+    fi
+
+    for volume in "$@"; do
+        unit="systemd-cryptsetup@$volume.service"
+
+        # The unit existence check should always pass
+        [[ "$(systemctl show -P LoadState "$unit")" == loaded ]]
+        systemctl list-unit-files "$unit"
+
+        systemctl start "$unit" && ec=0 || ec=$?
+        if [[ "$expect_fail" -ne 0 ]]; then
+            if [[ "$ec" -eq 0 ]]; then
+                echo >&2 "Unexpected pass when starting $unit"
+                return 1
+            fi
+
+            return 0
+        fi
+
+        if [[ "$ec" -ne 0 ]]; then
+            echo >&2 "Unexpected fail when starting $unit"
+            return 1
+        fi
+
+        systemctl status "$unit"
+        test -e "/dev/mapper/$volume"
+        systemctl stop "$unit"
+        test ! -e "/dev/mapper/$volume"
+    done
+
+    return 0
+}
+
+# Note: some stuff (especially TPM-related) is already tested by TEST-70-TPM2,
+#       so focus more on other areas instead
+
+# Use a common workdir to make the cleanup easier
+WORKDIR="$(mktemp -d)"
+
+# Prepare a couple of LUKS2-encrypted disk images
+#
+# 1) Image with an empty password
+IMAGE_EMPTY="$WORKDIR/empty.img)"
+IMAGE_EMPTY_KEYFILE="$WORKDIR/empty.keyfile"
+IMAGE_EMPTY_KEYFILE_ERASE="$WORKDIR/empty-erase.keyfile"
+IMAGE_EMPTY_KEYFILE_ERASE_FAIL="$WORKDIR/empty-erase-fail.keyfile)"
+truncate -s 32M "$IMAGE_EMPTY"
+echo -n passphrase >"$IMAGE_EMPTY_KEYFILE"
+chmod 0600 "$IMAGE_EMPTY_KEYFILE"
+cryptsetup luksFormat --batch-mode \
+                      --pbkdf pbkdf2 \
+                      --pbkdf-force-iterations 1000 \
+                      --use-urandom \
+                      "$IMAGE_EMPTY" "$IMAGE_EMPTY_KEYFILE"
+PASSWORD=passphrase NEWPASSWORD="" systemd-cryptenroll --password "$IMAGE_EMPTY"
+# Duplicate the key file to test keyfile-erase as well
+cp -v "$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY_KEYFILE_ERASE"
+# The key should get erased even on a failed attempt, so test that too
+cp -v "$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY_KEYFILE_ERASE_FAIL"
+
+# 2) Image with a detached header and a key file offset + size
+IMAGE_DETACHED="$WORKDIR/detached.img"
+IMAGE_DETACHED_KEYFILE="$WORKDIR/detached.keyfile"
+IMAGE_DETACHED_KEYFILE2="$WORKDIR/detached.keyfile2"
+IMAGE_DETACHED_HEADER="$WORKDIR/detached.header"
+truncate -s 32M "$IMAGE_DETACHED"
+dd if=/dev/urandom of="$IMAGE_DETACHED_KEYFILE" count=64 bs=1
+dd if=/dev/urandom of="$IMAGE_DETACHED_KEYFILE2" count=32 bs=1
+chmod 0600 "$IMAGE_DETACHED_KEYFILE" "$IMAGE_DETACHED_KEYFILE2"
+cryptsetup luksFormat --batch-mode \
+                      --pbkdf pbkdf2 \
+                      --pbkdf-force-iterations 1000 \
+                      --use-urandom \
+                      --header "$IMAGE_DETACHED_HEADER" \
+                      --keyfile-offset 32 \
+                      --keyfile-size 16 \
+                      "$IMAGE_DETACHED" "$IMAGE_DETACHED_KEYFILE"
+# Also, add a second key file to key slot 8
+# Note: --key-slot= behaves as --new-key-slot= when used alone for backwards compatibility
+cryptsetup luksAddKey --batch-mode \
+                      --header "$IMAGE_DETACHED_HEADER" \
+                      --key-file "$IMAGE_DETACHED_KEYFILE" \
+                      --keyfile-offset 32 \
+                      --keyfile-size 16 \
+                      --key-slot 8 \
+                      "$IMAGE_DETACHED" "$IMAGE_DETACHED_KEYFILE2"
+
+# Prepare a couple of dummy devices we'll store a copy of the detached header
+# and one of the keys on to test if systemd-cryptsetup correctly mounts them
+# when necessary
+STORE_IMAGE="$WORKDIR/store.img"
+truncate -s 64M "$STORE_IMAGE"
+STORE_LOOP="$(losetup --show --find --partscan "$STORE_IMAGE")"
+sfdisk "$STORE_LOOP" <<EOF
+label: gpt
+type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=header_store size=32M
+type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=keyfile_store
+EOF
+udevadm settle --timeout=30
+mkdir -p /mnt
+mkfs.ext4 -L header_store "/dev/disk/by-partlabel/header_store"
+mount "/dev/disk/by-partlabel/header_store" /mnt
+cp "$IMAGE_DETACHED_HEADER" /mnt/header
+umount /mnt
+mkfs.ext4 -L keyfile_store "/dev/disk/by-partlabel/keyfile_store"
+mount "/dev/disk/by-partlabel/keyfile_store" /mnt
+cp "$IMAGE_DETACHED_KEYFILE2" /mnt/keyfile
+umount /mnt
+udevadm settle --timeout=30
+
+# Prepare our test crypttab
+[[ -e /etc/crypttab ]] && cp -fv /etc/crypttab /tmp/crypttab.bak
+cat >/etc/crypttab <<EOF
+# headless should translate to headless=1
+empty_key            $IMAGE_EMPTY    $IMAGE_EMPTY_KEYFILE            headless,x-systemd.device-timeout=1m
+empty_key_erase      $IMAGE_EMPTY    $IMAGE_EMPTY_KEYFILE_ERASE      headless=1,keyfile-erase=1
+empty_key_erase_fail $IMAGE_EMPTY    $IMAGE_EMPTY_KEYFILE_ERASE_FAIL headless=1,keyfile-erase=1,keyfile-offset=4
+# Empty passphrase without try-empty-password(=yes) shouldn't work
+empty_fail0          $IMAGE_EMPTY    -                               headless=1
+empty_fail1          $IMAGE_EMPTY    -                               headless=1,try-empty-password=0
+empty0               $IMAGE_EMPTY    -                               headless=1,try-empty-password
+empty1               $IMAGE_EMPTY    -                               headless=1,try-empty-password=1
+# This one expects the key to be under /{etc,run}/cryptsetup-keys.d/empty_nokey.key
+empty_nokey          $IMAGE_EMPTY    -                               headless=1
+
+detached             $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=$IMAGE_DETACHED_HEADER,keyfile-offset=32,keyfile-size=16
+detached_store0      $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=/header:LABEL=header_store,keyfile-offset=32,keyfile-size=16
+detached_store1      $IMAGE_DETACHED /keyfile:LABEL=keyfile_store    headless=1,header=$IMAGE_DETACHED_HEADER
+detached_store2      $IMAGE_DETACHED /keyfile:LABEL=keyfile_store    headless=1,header=/header:LABEL=header_store
+detached_fail0       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=$IMAGE_DETACHED_HEADER,keyfile-offset=32
+detached_fail1       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=$IMAGE_DETACHED_HEADER
+detached_fail2       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1
+detached_fail3       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=$IMAGE_DETACHED_HEADER,keyfile-offset=16,keyfile-size=16
+detached_fail4       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE         headless=1,header=$IMAGE_DETACHED_HEADER,keyfile-offset=32,keyfile-size=8
+detached_slot0       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2        headless=1,header=$IMAGE_DETACHED_HEADER
+detached_slot1       $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2        headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=8
+detached_slot_fail   $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2        headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=0
+EOF
+
+# Temporarily drop luks.name=/luks.uuid= from the kernel command line, as it makes
+# systemd-cryptsetup-generator ignore mounts from /etc/crypttab that are not also
+# specified on the kernel command line
+sed -r 's/luks.(name|uuid)=[^[:space:]+]//' /proc/cmdline >/tmp/cmdline.tmp
+mount --bind /tmp/cmdline.tmp /proc/cmdline
+# Run the systemd-cryptsetup-generator once explicitly, to collect coverage,
+# as during daemon-reload we run generators in a sandbox
+mkdir -p /tmp/systemd-cryptsetup-generator.out
+/usr/lib/systemd/system-generators/systemd-cryptsetup-generator /tmp/systemd-cryptsetup-generator.out/
+systemctl daemon-reload
+systemctl list-unit-files "systemd-cryptsetup@*"
+
+cryptsetup_start_and_check empty_key
+test -e "$IMAGE_EMPTY_KEYFILE_ERASE"
+cryptsetup_start_and_check empty_key_erase
+test ! -e "$IMAGE_EMPTY_KEYFILE_ERASE"
+test -e "$IMAGE_EMPTY_KEYFILE_ERASE_FAIL"
+cryptsetup_start_and_check -f empty_key_erase_fail
+test ! -e "$IMAGE_EMPTY_KEYFILE_ERASE_FAIL"
+cryptsetup_start_and_check -f empty_fail{0..1}
+cryptsetup_start_and_check empty{0..1}
+# First, check if we correctly fail without any key
+cryptsetup_start_and_check -f empty_nokey
+# And now provide the key via /{etc,run}/cryptsetup-keys.d/
+mkdir -p /run/cryptsetup-keys.d
+cp "$IMAGE_EMPTY_KEYFILE" /run/cryptsetup-keys.d/empty_nokey.key
+cryptsetup_start_and_check empty_nokey
+
+cryptsetup_start_and_check detached
+cryptsetup_start_and_check detached_store{0..2}
+cryptsetup_start_and_check -f detached_fail{0..4}
+cryptsetup_start_and_check detached_slot{0..1}
+cryptsetup_start_and_check -f detached_slot_fail
+
+echo OK >/testok
index d243d93d8132e5b57cddb31c136e94ab5476865e..89466a5e33187480f6becc69831db1eba79d747a 100755 (executable)
@@ -253,6 +253,22 @@ cmp /tmp/ts54-concat <(echo -n abcd)
 rm /tmp/ts54-concat
 rm -rf /tmp/ts54-creds
 
+# Check that globs work as expected
+mkdir -p /run/credstore
+echo -n a >/run/credstore/test.creds.first
+echo -n b >/run/credstore/test.creds.second
+mkdir -p /etc/credstore
+echo -n c >/etc/credstore/test.creds.third
+systemd-run -p "ImportCredential=test.creds.*" \
+            --unit=test-54-ImportCredential.service \
+            -p DynamicUser=1 \
+            --wait \
+            --pipe \
+            cat '${CREDENTIALS_DIRECTORY}/test.creds.first' \
+                '${CREDENTIALS_DIRECTORY}/test.creds.second' \
+                '${CREDENTIALS_DIRECTORY}/test.creds.third' >/tmp/ts54-concat
+cmp /tmp/ts54-concat <(echo -n abc)
+
 # Now test encrypted credentials (only supported when built with OpenSSL though)
 if systemctl --version | grep -q -- +OPENSSL ; then
     echo -n $RANDOM >/tmp/test-54-plaintext
index 521584892fb10d882595029406eadcc8c4302af0..6ddb96d26e30e07df25ea9a257819c9d05e5e1c1 100755 (executable)
@@ -96,17 +96,18 @@ testcase_basic() {
     local loop volume
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
 
     echo "*** 1. create an empty image ***"
 
-    runas testuser systemd-repart --empty=create \
-                                  --size=1G \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --empty=create \
+                   --size=1G \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -140,11 +141,13 @@ SizeMaxBytes=64M
 PaddingMinBytes=92M
 EOF
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  --include-partitions=home,swap \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   --include-partitions=home,swap \
+                   --offline="$OFFLINE" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -157,12 +160,13 @@ last-lba: 2097118
 $imgs/zzz1 : start=        2048, size=     1775576, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
 $imgs/zzz2 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  --empty=force \
-                                  --defer-partitions=home,root \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   --empty=force \
+                   --defer-partitions=home,root \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -174,10 +178,11 @@ first-lba: 2048
 last-lba: 2097118
 $imgs/zzz4 : start=     1777624, size=      131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\""
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -210,10 +215,11 @@ EOF
     echo "Label=ignored_label" >>"$defs/home.conf"
     echo "UUID=b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" >>"$defs/home.conf"
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -231,11 +237,12 @@ $imgs/zzz5 : start=     1908696, size=      188416, type=0FC63DAF-8483-4772-8E79
 
     echo "*** 4. Resizing to 2G ***"
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --size=2G \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --size=2G \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -263,11 +270,12 @@ UUID=2a1d97e1d0a346cca26eadc643926617
 CopyBlocks=$imgs/block-copy
 EOF
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --size=3G \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --size=3G \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -299,15 +307,12 @@ CopyFiles=$defs:/def
 SizeMinBytes=48M
 EOF
 
-    # CopyFiles will fail if we try to chown the target file to root.
-    # Make the files owned by the user so that the invocation below works.
-    chown testuser -R "$defs"
-
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --size=auto \
-                                  --dry-run=no \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --size=auto \
+                   --dry-run=no \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk -d "$imgs/zzz" | grep -v -e 'sector-size' -e '^$')
 
@@ -350,7 +355,7 @@ testcase_dropin() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -374,11 +379,12 @@ EOF
 Label=label2
 EOF
 
-    output=$(runas testuser systemd-repart --definitions="$defs" \
-                                           --empty=create \
-                                           --size=100M \
-                                           --json=pretty \
-                                           "$imgs/zzz")
+    output=$(systemd-repart --offline="$OFFLINE" \
+                            --definitions="$defs" \
+                            --empty=create \
+                            --size=100M \
+                            --json=pretty \
+                            "$imgs/zzz")
 
     diff -u <(echo "$output") - <<EOF
 [
@@ -409,7 +415,7 @@ testcase_multiple_definitions() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -432,12 +438,13 @@ UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
 Label=label2
 EOF
 
-    output=$(runas testuser systemd-repart --definitions="$defs/1" \
-                                           --definitions="$defs/2" \
-                                           --empty=create \
-                                           --size=100M \
-                                           --json=pretty \
-                                           "$imgs/zzz")
+    output=$(systemd-repart --offline="$OFFLINE" \
+                            --definitions="$defs/1" \
+                            --definitions="$defs/2" \
+                            --empty=create \
+                            --size=100M \
+                            --json=pretty \
+                            "$imgs/zzz")
 
     diff -u <(echo "$output") - <<EOF
 [
@@ -479,7 +486,7 @@ testcase_copy_blocks() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -509,11 +516,12 @@ Format=ext4
 MakeDirectories=/usr /efi
 EOF
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --empty=create \
-                                  --size=auto \
-                                  --seed="$seed" \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --empty=create \
+                   --size=auto \
+                   --seed="$seed" \
+                   "$imgs/zzz"
 
     output=$(sfdisk --dump "$imgs/zzz")
 
@@ -547,8 +555,8 @@ Type=root-${architecture}
 CopyBlocks=auto
 EOF
 
-    # --image needs root privileges so skip runas testuser here.
-    systemd-repart --definitions="$defs" \
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
                    --empty=create \
                    --size=auto \
                    --seed="$seed" \
@@ -562,7 +570,7 @@ testcase_unaligned_partition() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -574,7 +582,7 @@ testcase_unaligned_partition() {
 Type=root-${architecture}
 EOF
 
-    runas testuser truncate -s 10g "$imgs/unaligned"
+    truncate -s 10g "$imgs/unaligned"
     sfdisk "$imgs/unaligned" <<EOF
 label: gpt
 
@@ -582,10 +590,11 @@ start=2048, size=69044
 start=71092, size=3591848
 EOF
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  "$imgs/unaligned"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   "$imgs/unaligned"
 
     output=$(sfdisk --dump "$imgs/unaligned")
 
@@ -598,7 +607,7 @@ testcase_issue_21817() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -610,7 +619,7 @@ testcase_issue_21817() {
 Type=root
 EOF
 
-    runas testuser truncate -s 100m "$imgs/21817.img"
+    truncate -s 100m "$imgs/21817.img"
     sfdisk "$imgs/21817.img" <<EOF
 label: gpt
 
@@ -618,11 +627,12 @@ size=50M, type=${root_guid}
 ,
 EOF
 
-    runas testuser systemd-repart --pretty=yes \
-                                  --definitions "$imgs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  "$imgs/21817.img"
+    systemd-repart --offline="$OFFLINE" \
+                   --pretty=yes \
+                   --definitions "$imgs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   "$imgs/21817.img"
 
     output=$(sfdisk --dump "$imgs/21817.img")
 
@@ -635,7 +645,7 @@ testcase_issue_24553() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -660,28 +670,30 @@ start=524328, size=14848000, type=${root_guid}, uuid=${root_uuid}, name="root-${
 EOF
 
     echo "*** 1. Operate on a small image compared with SizeMinBytes= ***"
-    runas testuser truncate -s 8g "$imgs/zzz"
+    truncate -s 8g "$imgs/zzz"
     sfdisk "$imgs/zzz" <"$imgs/partscript"
 
     # This should fail, but not trigger assertions.
-    assert_rc 1 runas testuser systemd-repart --definitions="$defs" \
-                                              --seed="$seed" \
-                                              --dry-run=no \
-                                              "$imgs/zzz"
+    assert_rc 1 systemd-repart --offline="$OFFLINE" \
+                               --definitions="$defs" \
+                               --seed="$seed" \
+                               --dry-run=no \
+                               "$imgs/zzz"
 
     output=$(sfdisk --dump "$imgs/zzz")
     assert_in "$imgs/zzz2 : start=      524328, size=    14848000, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
 
     echo "*** 2. Operate on an larger image compared with SizeMinBytes= ***"
     rm -f "$imgs/zzz"
-    runas testuser truncate -s 12g "$imgs/zzz"
+    truncate -s 12g "$imgs/zzz"
     sfdisk "$imgs/zzz" <"$imgs/partscript"
 
     # This should succeed.
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   "$imgs/zzz"
 
     output=$(sfdisk --dump "$imgs/zzz")
     assert_in "$imgs/zzz2 : start=      524328, size=    24641456, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
@@ -703,14 +715,15 @@ Priority=10
 EOF
 
     rm -f "$imgs/zzz"
-    runas testuser truncate -s 8g "$imgs/zzz"
+    truncate -s 8g "$imgs/zzz"
     sfdisk "$imgs/zzz" <"$imgs/partscript"
 
     # This should also succeed, but root is not extended.
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   "$imgs/zzz"
 
     output=$(sfdisk --dump "$imgs/zzz")
     assert_in "$imgs/zzz2 : start=      524328, size=    14848000, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
@@ -718,14 +731,15 @@ EOF
 
     echo "*** 4. Multiple partitions with Priority= (large disk) ***"
     rm -f "$imgs/zzz"
-    runas testuser truncate -s 12g "$imgs/zzz"
+    truncate -s 12g "$imgs/zzz"
     sfdisk "$imgs/zzz" <"$imgs/partscript"
 
     # This should also succeed, and root is extended.
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  "$imgs/zzz"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   "$imgs/zzz"
 
     output=$(sfdisk --dump "$imgs/zzz")
     assert_in "$imgs/zzz2 : start=      524328, size=    20971520, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
@@ -736,7 +750,7 @@ testcase_zero_uuid() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -749,12 +763,13 @@ Type=root-${architecture}
 UUID=null
 EOF
 
-    runas testuser systemd-repart --definitions="$defs" \
-                                  --seed="$seed" \
-                                  --dry-run=no \
-                                  --empty=create \
-                                  --size=auto \
-                                  "$imgs/zero"
+    systemd-repart --offline="$OFFLINE" \
+                   --definitions="$defs" \
+                   --seed="$seed" \
+                   --dry-run=no \
+                   --empty=create \
+                   --size=auto \
+                   "$imgs/zero"
 
     output=$(sfdisk --dump "$imgs/zero")
 
@@ -765,7 +780,7 @@ testcase_verity() {
     local defs imgs output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs'" RETURN
     chmod a+rx "$defs"
@@ -822,21 +837,18 @@ EOF
             -nodes
 
     mkdir -p /run/verity.d
-    ln -s "$defs/verity.crt" /run/verity.d/ok.crt
-
-    # CopyFiles will fail if we try to chown the target file to root.
-    # Make the files owned by the user so that the invocation below works.
-    chown testuser -R "$defs"
-
-    output=$(runas testuser systemd-repart --definitions="$defs" \
-                                           --seed="$seed" \
-                                           --dry-run=no \
-                                           --empty=create \
-                                           --size=auto \
-                                           --json=pretty \
-                                           --private-key="$defs/verity.key" \
-                                           --certificate="$defs/verity.crt" \
-                                           "$imgs/verity")
+    ln -sf "$defs/verity.crt" /run/verity.d/ok.crt
+
+    output=$(systemd-repart --offline="$OFFLINE" \
+                            --definitions="$defs" \
+                            --seed="$seed" \
+                            --dry-run=no \
+                            --empty=create \
+                            --size=auto \
+                            --json=pretty \
+                            --private-key="$defs/verity.key" \
+                            --certificate="$defs/verity.crt" \
+                            "$imgs/verity")
 
     drh=$(jq -r ".[] | select(.type == \"root-${architecture}\") | .roothash" <<<"$output")
     hrh=$(jq -r ".[] | select(.type == \"root-${architecture}-verity\") | .roothash" <<<"$output")
@@ -862,8 +874,8 @@ testcase_exclude_files() {
     local defs imgs root output
 
     defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
-    imgs="$(runas testuser mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
-    root="$(runas testuser mktemp --directory "/var/tmp/test-repart.root.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
+    root="$(mktemp --directory "/var/tmp/test-repart.root.XXXXXXXXXX")"
     # shellcheck disable=SC2064
     trap "rm -rf '$defs' '$imgs' '$root'" RETURN
     chmod a+rx "$defs"
@@ -900,18 +912,15 @@ CopyFiles=/usr:/
 ExcludeFiles=/usr/qed
 EOF
 
-    # CopyFiles will fail if we try to chown the target file to root.
-    # Make the files owned by the user so that the invocation below works.
-    chown testuser -R "$root"
-
-    output=$(runas testuser systemd-repart --definitions="$defs" \
-                                           --seed="$seed" \
-                                           --dry-run=no \
-                                           --empty=create \
-                                           --size=auto \
-                                           --json=pretty \
-                                           --root="$root" \
-                                           "$imgs/zzz")
+    output=$(systemd-repart --offline="$OFFLINE" \
+                            --definitions="$defs" \
+                            --seed="$seed" \
+                            --dry-run=no \
+                            --empty=create \
+                            --size=auto \
+                            --json=pretty \
+                            --root="$root" \
+                            "$imgs/zzz")
 
     if systemd-detect-virt --quiet --container; then
         echo "Skipping issue 24786 test loop/mount parts in container."
@@ -996,7 +1005,8 @@ Minimize=best
 EOF
     fi
 
-    output=$(systemd-repart --definitions="$defs" \
+    output=$(systemd-repart --offline="$OFFLINE" \
+                            --definitions="$defs" \
                             --seed="$seed" \
                             --dry-run=no \
                             --empty=create \
@@ -1049,9 +1059,9 @@ EOF
     truncate -s 100m "$imgs/$sector.img"
     loop=$(losetup -b "$sector" -P --show -f "$imgs/$sector.img" )
     udevadm wait --timeout 60 --settle "${loop:?}"
-    # This operates on a loop device which we don't support doing without root privileges so we skip runas
-    # here.
-    systemd-repart --pretty=yes \
+
+    systemd-repart --offline="$OFFLINE" \
+                   --pretty=yes \
                    --definitions="$defs" \
                    --seed="$seed" \
                    --empty=require \
@@ -1074,8 +1084,15 @@ EOF
     assert_in "${loop}p3 : start= *${start}, size= *${size}, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=DB081670-07AE-48CA-9F5E-813D5E40B976, name=\"linux-generic-2\"" "$output"
 }
 
+OFFLINE="yes"
 run_testcases
 
+# Online image builds need loop devices so we can't run them in nspawn.
+if ! systemd-detect-virt --container; then
+    OFFLINE="no"
+    run_testcases
+fi
+
 # Valid block sizes on the Linux block layer are >= 512 and <= PAGE_SIZE, and
 # must be powers of 2. Which leaves exactly four different ones to test on
 # typical hardware
diff --git a/test/units/testsuite-61.service b/test/units/testsuite-61.service
deleted file mode 100644 (file)
index 568960c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Unit]
-Description=TEST-61-UNITTESTS-QEMU
-
-[Service]
-ExecStartPre=rm -f /failed /testok
-ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
-Type=oneshot
diff --git a/test/units/testsuite-61.sh b/test/units/testsuite-61.sh
deleted file mode 100755 (executable)
index 0b7b011..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-# shellcheck disable=SC2317
-set -eux
-set -o pipefail
-
-TESTS_GLOB="test-loop-block"
-# shellcheck source=test/units/testsuite-02.sh
-. "$(dirname "$0")/testsuite-02.sh"
-
-exit 0
index 0361358bec27ce06fa8d11e804b2fa140990e444..bc14298653d35ebe35a3f09b51063a944027891a 100755 (executable)
@@ -7,6 +7,8 @@ class CustomResolver(tree.Resolver):
     def resolve(self, url, id, context):
         if 'custom-entities.ent' in url:
             return self.resolve_filename('man/custom-entities.ent', context)
+        if 'ethtool-link-mode' in url:
+            return self.resolve_filename('src/shared/ethtool-link-mode.xml', context)
 
 _parser = tree.XMLParser()
 _parser.resolvers.add(CustomResolver())
index 55e83dfe00733856bc7ef3742094a5bf4e42ccd4..6fb0838cdb46971a60af8429b66ec1194a14edab 100644 (file)
@@ -18,6 +18,6 @@ After=network.target
 [Service]
 Type=forking
 ExecStart={{RC_LOCAL_PATH}} start
-TimeoutSec=0
+TimeoutSec=infinity
 RemainAfterExit=yes
 GuessMainPID=no
index 984ebf282ad98f28d1a79b1f238976cf4ae0c118..0c8d574ef8b27cffdaa933b21ccffc916a85ef84 100644 (file)
@@ -32,10 +32,7 @@ StandardError=tty
 # Optionally, pick up basic fields from credentials passed to the service
 # manager. This is useful for importing this data from nspawn's
 # --set-credential= switch.
-LoadCredential=passwd.hashed-password.root
-LoadCredential=passwd.plaintext-password.root
-LoadCredential=passwd.shell.root
-LoadCredential=firstboot.locale
-LoadCredential=firstboot.locale-messages
-LoadCredential=firstboot.keymap
-LoadCredential=firstboot.timezone
+ImportCredential=passwd.hashed-password.root
+ImportCredential=passwd.plaintext-password.root
+ImportCredential=passwd.shell.root
+ImportCredential=firstboot.*
index 8378df84c71887bf1843de4b533de5cf3aa4f9a5..8cfbe7ce9879022c480289c2fd57b504713524e0 100644 (file)
@@ -21,4 +21,4 @@ OnFailureJobMode=replace-irreversibly
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-fsck
-TimeoutSec=0
+TimeoutSec=infinity
index 06b91aea39c1f6c5c4537046b1fbd365c4e7bf73..d773229812e28778ca4ff4643b93ee1a104363b4 100644 (file)
@@ -20,4 +20,4 @@ Before=systemd-quotacheck.service shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-fsck %f
-TimeoutSec=0
+TimeoutSec=infinity
index 61b825672d27245487df724ff66a3a604b39b784..0468774cb0024c416ad5930db524eb0b4fc30217 100644 (file)
@@ -20,4 +20,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-growfs /
-TimeoutSec=0
+TimeoutSec=infinity
index d7c90e96fceb4a5cbef89fa35f1c03271e34a981..90fb0a86619b837981b6c7803f2de4a566f81fee 100644 (file)
@@ -21,4 +21,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-growfs %f
-TimeoutSec=0
+TimeoutSec=infinity
index 05c14ff8b6e77a5336e921606a998933e19c447a..60b56496fa8be70cc7a1ef9cd59ec818ebe8d1be 100644 (file)
@@ -22,4 +22,4 @@ Before=shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-quotacheck
-TimeoutSec=0
+TimeoutSec=infinity
index 10ce49345e506b70f95c35544f59aa64cbb6d2fe..a078a9dd684bf08da87c89c068365f054a67c670 100644 (file)
@@ -50,8 +50,8 @@ SystemCallErrorNumber=EPERM
 SystemCallFilter=@system-service
 Type=notify
 User=systemd-resolve
-LoadCredential=network.dns
-LoadCredential=network.search_domains
+ImportCredential=network.dns
+ImportCredential=network.search_domains
 {{SERVICE_WATCHDOG}}
 
 [Install]
index 77793f38948fdfe015da08a73b7eb70227ec82c3..7307601a7dfb077d67438ebfb6b982146a47edb1 100644 (file)
@@ -21,4 +21,4 @@ Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-sysctl
 TimeoutSec=90s
-LoadCredential=sysctl.extra
+ImportCredential=sysctl.*
index 2ec276684164cf8184d211448acb4a2ec43c8ab3..84fd66de37aac0a9ebd6ed5916db3febe1e37a34 100644 (file)
@@ -29,9 +29,9 @@ TimeoutSec=90s
 # Optionally, pick up a root password and shell for the root user from a
 # credential passed to the service manager. This is useful for importing this
 # data from nspawn's --set-credential= switch.
-LoadCredential=passwd.hashed-password.root
-LoadCredential=passwd.plaintext-password.root
-LoadCredential=passwd.shell.root
+ImportCredential=passwd.hashed-password.root
+ImportCredential=passwd.plaintext-password.root
+ImportCredential=passwd.shell.root
 
 # Also, allow configuring extra sysusers lines via a credential
-LoadCredential=sysusers.extra
+ImportCredential=sysusers.*
index 4163aef729b75a12633f70cc10246b2609877cb0..7b0edba412ba405d8020fb3d400d9ec832bee0cc 100644 (file)
@@ -21,4 +21,4 @@ Type=oneshot
 ExecStart=systemd-tmpfiles --clean
 SuccessExitStatus=DATAERR
 IOSchedulingClass=idle
-LoadCredential=tmpfiles.extra
+ImportCredential=tmpfiles.*
index 635e840a488f399210f644f2a6b6eeb56e737c37..acaa9510aa60bbd8cc8ed61d524c8a1a7af42925 100644 (file)
@@ -22,4 +22,4 @@ Type=oneshot
 RemainAfterExit=yes
 ExecStart=systemd-tmpfiles --prefix=/dev --create --boot --graceful
 SuccessExitStatus=DATAERR CANTCREAT
-LoadCredential=tmpfiles.extra
+ImportCredential=tmpfiles.*
index 506f53eaa2f29cf465e51bda644e34c0a9ff3065..6c5e3de8fd96248ea0c8c3594e826f914d1c6054 100644 (file)
@@ -23,8 +23,8 @@ Type=oneshot
 RemainAfterExit=yes
 ExecStart=systemd-tmpfiles --create --remove --boot
 SuccessExitStatus=DATAERR CANTCREAT
-LoadCredential=tmpfiles.extra
-LoadCredential=login.motd
-LoadCredential=login.issue
-LoadCredential=network.hosts
-LoadCredential=ssh.authorized_keys.root
+ImportCredential=tmpfiles.*
+ImportCredential=login.motd
+ImportCredential=login.issue
+ImportCredential=network.hosts
+ImportCredential=ssh.authorized_keys.root
index 41d738a63d47294cfaeb9507bd5cc310980550c1..0604ed0173c5711461b7f6d5391d4feaae6d1532 100644 (file)
@@ -21,8 +21,4 @@ Before=initrd-switch-root.target shutdown.target
 Type=oneshot
 RemainAfterExit=yes
 ExecStart={{ROOTLIBEXECDIR}}/systemd-vconsole-setup
-LoadCredential=vconsole.keymap
-LoadCredential=vconsole.keymap_toggle
-LoadCredential=vconsole.font
-LoadCredential=vconsole.font_map
-LoadCredential=vconsole.font_unimap
+ImportCredential=vconsole.*