]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #23653 from aafeijoo-suse/ask-for-recovery-key
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Aug 2022 12:55:54 +0000 (14:55 +0200)
committerGitHub <noreply@github.com>
Fri, 19 Aug 2022 12:55:54 +0000 (14:55 +0200)
cryptsetup: improve password prompt text

225 files changed:
.github/advanced-issue-labeler.yml
.github/workflows/coverity.yml
.github/workflows/differential-shellcheck.yml [new file with mode: 0644]
.github/workflows/linter.yml
.github/workflows/mkosi.yml
.gitignore
.semaphore/semaphore-runner.sh
NEWS
TODO
docs/CREDENTIALS.md
hwdb.d/60-sensor.hwdb
hwdb.d/70-analyzers.hwdb
hwdb.d/parse_hwdb.py
man/bootctl.xml
man/bootup.xml
man/crypttab.xml
man/org.freedesktop.oom1.xml
man/org.freedesktop.systemd1.xml
man/os-release.xml
man/systemd-cryptenroll.xml
man/systemd-repart.xml
man/systemd-sysext.xml
man/systemd-system.conf.xml
man/systemd.net-naming-scheme.xml
man/systemd.netdev.xml
man/systemd.resource-control.xml
meson.build
mkosi.default.d/10-systemd.conf
po/hu.po
rules.d/60-sensor.rules
rules.d/70-uaccess.rules.in
shell-completion/bash/systemd-cgtop
src/backlight/backlight.c
src/basic/cgroup-util.h
src/basic/def.h
src/basic/ether-addr-util.c
src/basic/ether-addr-util.h
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/hash-funcs.c
src/basic/hash-funcs.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/random-util.c
src/boot/bootctl.c
src/boot/efi/boot.c
src/boot/efi/linux.c
src/boot/efi/meson.build
src/boot/efi/stub.c
src/core/cgroup.c
src/core/dbus-cgroup.c
src/core/dbus-manager.c
src/core/dbus-unit.c
src/core/device.c
src/core/kmod-setup.c
src/core/load-fragment-gperf.gperf.in
src/core/load-fragment.c
src/core/load-fragment.h
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/namespace.c
src/core/scope.c
src/core/scope.h
src/core/system.conf.in
src/core/timer.c
src/core/unit.c
src/creds/creds.c
src/cryptenroll/cryptenroll.c
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-fido2.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.c
src/cryptsetup/cryptsetup-tokens/cryptsetup-token-util.h
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c
src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h
src/cryptsetup/cryptsetup.c
src/firstboot/firstboot.c
src/fsck/fsck.c
src/fstab-generator/fstab-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/initctl/initctl.c
src/journal/journald-server.c
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/dhcp-identifier.h
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/dhcp-protocol.h
src/libsystemd-network/dhcp6-protocol.c
src/libsystemd-network/dhcp6-protocol.h
src/libsystemd-network/fuzz-dhcp-client.c
src/libsystemd-network/fuzz-dhcp6-client.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-lease.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-monitor.c
src/libsystemd/sd-device/device-util.c
src/libsystemd/sd-device/device-util.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device-monitor.c
src/libsystemd/sd-device/test-sd-device.c
src/login/logind-dbus.c
src/login/logind-session-device.c
src/login/logind-utmp.c
src/login/logind.c
src/login/pam_systemd.c
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/netdev/tuntap.c
src/network/netdev/tuntap.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp-common.c
src/network/networkd-dhcp4.c
src/network/networkd-ipv4acd.c
src/network/networkd-ipv4acd.h
src/network/networkd-link.c
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-network.c
src/network/networkd-setlink.c
src/network/networkd-sriov.c
src/network/networkd-util.c
src/network/networkd-util.h
src/network/tc/qdisc.c
src/network/tc/qdisc.h
src/network/tc/teql.c
src/nspawn/nspawn-mount.c
src/oom/oomd-manager-bus.c
src/oom/oomd-manager.c
src/partition/repart.c
src/partition/test-repart.sh
src/portable/portablectl.c
src/resolve/resolvectl.c
src/resolve/resolved-dnssd.c
src/run/run.c
src/shared/bus-locator.c
src/shared/bus-locator.h
src/shared/bus-print-properties.c
src/shared/bus-unit-procs.c
src/shared/bus-unit-util.c
src/shared/cgroup-setup.c
src/shared/cgroup-setup.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/creds-util.c
src/shared/creds-util.h
src/shared/daemon-util.c [new file with mode: 0644]
src/shared/daemon-util.h
src/shared/extension-release.c
src/shared/generator.c
src/shared/hwdb-util.c
src/shared/hwdb-util.h
src/shared/meson.build
src/shared/mount-util.h
src/shared/netif-naming-scheme.c
src/shared/netif-naming-scheme.h
src/shared/sleep-config.c
src/shared/sleep-config.h
src/shared/tpm2-util.c
src/shared/udev-util.c
src/shared/user-record-show.c
src/shutdown/shutdown.c
src/sleep/sleep.c
src/sulogin-shell/sulogin-shell.c
src/sysctl/sysctl.c
src/systemctl/systemctl-daemon-reload.c
src/systemd/sd-device.h
src/systemd/sd-dhcp-client.h
src/systemd/sd-messages.h
src/sysusers/sysusers.c
src/test/test-path-util.c
src/udev/cdrom_id/cdrom_id.c
src/udev/net/link-config.c
src/udev/udev-builtin-hwdb.c
src/udev/udev-builtin-kmod.c
src/udev/udev-builtin-net_id.c
src/udev/udev-builtin-net_setup_link.c
src/udev/udev-builtin.c
src/udev/udev-builtin.h
src/udev/udevd.c
test/fuzz/fuzz-netdev-parser/directives.netdev
test/networkd-test.py
test/test-functions
test/test-network/conf/25-bridge99.network
test/test-network/conf/25-dhcp-client-decline.network [deleted file]
test/test-network/conf/25-dhcp4-6rd-upstream.network
test/test-network/conf/25-qdisc-clsact-and-htb.network [deleted file]
test/test-network/conf/25-qdisc-clsact.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-codel.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-fq.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-fq_codel.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-gred.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-htb-fifo.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-ingress.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-netem-compat.network [moved from test/test-network/conf/25-qdisc-ingress-netem-compat.network with 84% similarity]
test/test-network/conf/25-qdisc-netem.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-qfq.network
test/test-network/conf/25-qdisc-sfb.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-sfq.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-tbf.network [new file with mode: 0644]
test/test-network/conf/25-qdisc-teql.network [new file with mode: 0644]
test/test-network/conf/25-tap.netdev
test/test-network/conf/25-tun.netdev
test/test-network/conf/26-bridge-slave-interface-1.network
test/test-network/conf/26-bridge-slave-interface-2.network
test/test-network/conf/26-netdev-link-local-addressing-yes.network
test/test-network/systemd-networkd-tests.py
test/units/assert.sh
test/units/testsuite-17.07.sh [new file with mode: 0755]
test/units/testsuite-50.sh
test/units/testsuite-53.sh
test/units/testsuite-70.sh
test/units/testsuite-76.sh
tools/coverity.sh
tools/get-coverity.sh [deleted file]
units/initrd-parse-etc.service [deleted file]
units/initrd-parse-etc.service.in [new file with mode: 0644]
units/meson.build
units/systemd-networkd.service.in

index 87ac69dc6c1f1524f330193241f803a29e714abb..3ab23935471c2cd4f4cd264ba5c1c4b2b2373493 100644 (file)
@@ -34,7 +34,7 @@ policy:
   rfkill: ['systemd-rfkill']
   rpm: ['rpm scriptlets']
   run: ['systemd-run']
-  sd-boot: ['bootctl', 'systemd-boot', 'systemd-stub']
+  sd-boot/sd-stub/bootctl: ['bootctl', 'systemd-boot', 'systemd-stub']
   sysctl: ['systemd-sysctl']
   sysext: ['systemd-sysext']
   systemctl: ['systemctl']
index 904a6895fd4c64f2a2923746155f10fba0457c26..3fbebc6bbf1d0ce852247f9febfd3260330f02f0 100644 (file)
@@ -17,27 +17,14 @@ jobs:
     runs-on: ubuntu-22.04
     if: github.repository == 'systemd/systemd'
     env:
-      COVERITY_SCAN_BRANCH_PATTERN:     "${{ github.ref}}"
-      COVERITY_SCAN_NOTIFICATION_EMAIL: ""
-      COVERITY_SCAN_PROJECT_NAME:       "${{ github.repository }}"
-      # Set in repo settings -> secrets -> repository secrets
+      # Set in repo settings -> secrets -> actions
       COVERITY_SCAN_TOKEN:              "${{ secrets.COVERITY_SCAN_TOKEN }}"
-      CURRENT_REF:                      "${{ github.ref }}"
+      COVERITY_SCAN_NOTIFICATION_EMAIL: "${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}"
     steps:
       - name: Repository checkout
         uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
-      # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
-      - name: Set the $COVERITY_SCAN_NOTIFICATION_EMAIL env variable
-        run: echo "COVERITY_SCAN_NOTIFICATION_EMAIL=$(git log -1 ${{ github.sha }} --pretty=\"%aE\")" >> "$GITHUB_ENV"
-      - name: Install Coverity tools
-        run: tools/get-coverity.sh
       # Reuse the setup phase of the unit test script to avoid code duplication
       - name: Install build dependencies
         run: sudo -E .github/workflows/unit_tests.sh SETUP
-      # Preconfigure with meson to prevent Coverity from capturing meson metadata
-      - name: Preconfigure the build directory
-        run: meson cov-build -Dman=false
-      - name: Build
-        run: tools/coverity.sh build
-      - name: Upload the results
-        run: tools/coverity.sh upload
+      - name: Build & upload the results
+        run: tools/coverity.sh
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
new file mode 100644 (file)
index 0000000..154cf4a
--- /dev/null
@@ -0,0 +1,30 @@
+---
+# https://github.com/redhat-plumbers-in-action/differential-shellcheck#readme
+
+name: Differential ShellCheck
+on:
+  pull_request:
+    branches:
+      - main
+
+permissions:
+  contents: read
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+
+    permissions:
+      security-events: write
+      pull-requests: write
+
+    steps:
+      - name: Repository checkout
+        uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
+        with:
+          fetch-depth: 0
+
+      - name: Differential ShellCheck
+        uses: redhat-plumbers-in-action/differential-shellcheck@60360c0fb283149ed03ad16b66257a967c3e5231
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
index 0612a709ce3c1c3c9bf0b749f9f110e86828356a..4c6a8d5e5a0ba873eefb434e94c28f2ebea6a1b0 100644 (file)
@@ -38,8 +38,7 @@ jobs:
           #              missing shebangs)
           #   - .*\.(in|SKELETON) - all template/skeleton files
           #                         except kernel-install
-          #   - tools/coverity\.sh - external file (with some modifications)
-          FILTER_REGEX_EXCLUDE: .*/(man/.*|([^k]|k(k|ek)*([^ek]|e[^kr]))*(k(k|ek)*e?)?\.(in|SKELETON)|tools/coverity\.sh)$
+          FILTER_REGEX_EXCLUDE: .*/(man/.*|([^k]|k(k|ek)*([^ek]|e[^kr]))*(k(k|ek)*e?)?\.(in|SKELETON))$
           VALIDATE_ALL_CODEBASE: false
           VALIDATE_BASH: true
           VALIDATE_GITHUB_ACTIONS: true
index a4215460d2815d6f2f2df3723e042f881d8b2093..dddeb5fcb324dd8fb493bdb33222ebf4a4edc704 100644 (file)
@@ -51,7 +51,7 @@ jobs:
 
     steps:
     - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
-    - uses: systemd/mkosi@104483c479df5673e5ab52a16ca9484ee5cef3fd
+    - uses: systemd/mkosi@f37c19e7217a41c52d9a9a8769e98496255e2e2d
 
     - name: Install
       run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect python3-jinja2
index 7b6d0a376e976ada9d7b8ba250b4e472c6dd1a07..8aa363eac4cfbafb69077282dd0e9e0f703fafcd 100644 (file)
@@ -37,3 +37,4 @@ __pycache__/
 /mkosi.default.d/**/*local*.conf
 /tags
 .dir-locals-2.el
+.vscode/
index ba2181171814485369761bfc6b6d28845a4f90c1..98fd7b441121d9d27903fe39d3e9a48ff7c0954d 100755 (executable)
@@ -19,14 +19,7 @@ PHASES=(${@:-SETUP RUN})
 UBUNTU_RELEASE="$(lsb_release -cs)"
 
 create_container() {
-    # Create autopkgtest LXC image; this sometimes fails with "Unable to fetch
-    # GPG key from keyserver", so retry a few times with different keyservers.
-    for keyserver in "keys.openpgp.org" "" "keyserver.ubuntu.com" "keys.gnupg.net"; do
-        for retry in {1..5}; do
-            sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH" ${keyserver:+--keyserver "$keyserver"} && break 2
-            sleep $((retry*retry))
-        done
-    done
+    sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH"
 
     # unconfine the container, otherwise some tests fail
     echo 'lxc.apparmor.profile = unconfined' | sudo tee -a "/var/lib/lxc/$CONTAINER/config"
@@ -107,10 +100,10 @@ EOF
             # now build the package and run the tests
             rm -rf "$ARTIFACTS_DIR"
             # autopkgtest exits with 2 for "some tests skipped", accept that
-            "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \
-                                                  --env TEST_UPSTREAM=1 ../systemd_*.dsc \
-                                                  -o "$ARTIFACTS_DIR" \
-                                                  -- lxc -s "$CONTAINER" \
+            sudo "$AUTOPKGTEST_DIR/runner/autopkgtest" --env DEB_BUILD_OPTIONS=noudeb \
+                                                       --env TEST_UPSTREAM=1 ../systemd_*.dsc \
+                                                       -o "$ARTIFACTS_DIR" \
+                                                       -- lxc -s "$CONTAINER" \
                 || [ $? -eq 2 ]
         ;;
         *)
diff --git a/NEWS b/NEWS
index 503777e42c8593b60f05e314d7ad7da9e564739d..f2747b6acab1a877cfdf06dbc14d67ff34be5ca0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,6 @@
 systemd System and Service Manager
 
-CHANGES WITH 252:
+CHANGES WITH 252 in spe:
 
         Announcement of Future Feature Removal
 
@@ -10,6 +10,153 @@ CHANGES WITH 252:
           sooner rather than later, if you haven't done so yet. Most of Linux
           userspace has been ported over already.
 
+        New features:
+
+        * systemd-measure is a new helper to precalculate PCR measurements
+          to make it easier to set TPM2 policies.
+
+        Changes in systemd itself, i.e. the manager, and units
+
+        * The cpu controller is delegated to user manager units, and CPUWeight=
+          settings are applied to the top-level user slice units (app.slice,
+          background.slice, session.slice). This provides a degree of resource
+          isolation between different user services competing for the CPU.
+
+        * Systemd can optionally do a full preset in the "first boot" condition
+          (instead of just enable-only). This behaviour is controlled by the
+          compile-time option -Dfirst-boot-full-preset=. Right now it defaults
+          to 'false', but the plan is to switch it to 'true' for the subsequent
+          release.
+
+        * Systemd will set the taint flag 'support-ended' if it detects that
+          the os image is past its end-of-support date.
+
+        * Two new settings ConditionCredential= and AssertCredential= can
+          be used to skip or fail units if a certain credential is not provided.
+
+        * ConditionMemory= accepts size suffixes.
+
+        * DefaultSmackProcessLabel= can be used in system.conf and user.conf
+          to specify the smack label to use when not specified in a unit file.
+
+        * DefaultDeviceTimeoutSec= can be used system.conf and user.conf
+          to specify the default timeout for devices.
+
+        * C.UTF-8 is used as the default locale if nothing else has been configured.
+
+        Changes in sd-boot, bootctl, and the Boot Loader Specification:
+
+        * The Boot Loader Specification has been cleaned up and clarified.
+          Various corner cases in version string comparisons have been fixed
+          (e.g. comparisons for empty strings). Boot counting is now part of
+          the main specification.
+
+        * New PCRs measurements are set during boot: PCR 11 for the the
+          kernel+initrd combo, PCR 13 for any sysext images.
+
+        * The UEFI monotonic boot counter is now included in the random seed,
+          providing some additional entropy.
+
+        * Booting in EFI mixed mode (a 64-bit kernel over 32-bit UEFI firmware)
+          is now supported.
+
+        * bootctl gained a bunch of new options: '--all-architectures' to
+          install binaries for all supported EFI architectures, '--root=' and
+          '--image=' options to operate on a directory or disk image, and
+          '--install-source=' to specify the source for binaries to install.
+
+        * The sd-boot stub exports a StubFeatures flag, which is used by
+          bootctl to show features supported by the stub that was used to boot.
+
+        Changes in the hardware database:
+
+        * 'systemd-hwdb query' now supports the '--root' option.
+
+        Changes in systemctl:
+
+        * systemctl now supports '--state' and '--type' options for the 'show'
+          and 'status' verbs.
+
+        * systemctl gained a new verb 'list-automounts' to list automount
+          points.
+
+        Changes in systemd-networkd:
+
+        * networkd can set Linux NetLabel labels for integration with the
+          network control in security modules via a new NetLabel= option.
+
+        * networkd gained new options NFTSet=, IPv4NFTSet=, IPv6NFTSet= that
+          take names of nft sets as arguments. It will automatically add rules
+          for the subnets configured for an interface to those sets.
+
+        * The RapidCommit= is (re-)introduced to enable faster configuration
+          via DHCPv6 (RFC 3315).
+
+        Changes in systemd-nspawn:
+
+        * The --bind= and --overlay= options now support relative paths.
+
+        Changes in libsystemd and other libraries:
+
+        * libsystemd now exports the sd-netlink interface that provides
+          functions to send/receive/parse netlink and rtnl messages.
+
+        * libsystemd now exports sd_bus_error_setfv (a convenience function for
+          setting bus errors), sd_id128_string_equal (a convenience function
+          for identifier comparisons), sd_bus_message_read_strv_extend (a
+          function to incrementally read string arrays).
+
+        * Private shared libraries (libsystemd-shared-nnn.so,
+          libsystemd-core-nnn.so) are now installed into arch-specific
+          directories to allow multi-arch installs.
+
+        Changes in other components:
+
+        * sysusers and tmpfiles configuration can now be provided via the
+          credential mechanism.
+
+        * tmpfiles can read file contents to write from a credential (and a new
+          modifier char '^' to specify that the argument is a credential name).
+          This mechanism is used to automatically populate /etc/motd, /etc/issue,
+          and /etc/hosts from credentials.
+
+        * systemd-analyze gained a new verb 'compare-versions' that implements
+          comparisons for versions strings (similarly to 'rpmdev-vercmp' and
+          'dpkg --compare-versions').
+
+        * The pkgconfig and rpm macros files now export the directory for user
+          units as 'user_tmpfiles_dir' and '_user_tmpfilesdir'.
+
+        * Detection of Parallels and KubeVirt virtualization has been improved.
+
+        * os-release gained a new field SUPPORT_END=YYYY-MM-DD to inform the
+          user when their system will become unsupported.
+
+        * When performing suspend-then-hibernate, the system will estimate the
+          discharge rate and use that to set the delay until hibernation, and
+          will hibernate immediately instead of suspending when running from a
+          battery and the capacity is below 5%.
+
+        * systemd-sysctl gained a '--strict' option to fail when a sysctl
+          setting is unknown to the kernel.
+
+        * machinectl supports '--force' for the 'copy-to' and 'copy-from'
+          verbs.
+
+        * openssl is the default crypto backend for systemd-resolved. (gnutls
+          is still supported.)
+
+        Experimental features:
+
+        * BPF programs can now be compiled with bpf-gcc.
+
+        * sd-boot can automatically enroll SecureBoot keys from files found on
+          the ESP. This enrollment can be either automatic ('force' mode) or
+          controlled by the user ('manual' mode).
+
+        – Somewhere, sometime
+
+
 CHANGES WITH 251:
 
         Backwards-incompatible changes:
diff --git a/TODO b/TODO
index 59fe9b38946838aba7aee0bed957a2bec1c6d24b..309c51b756e0ba0835a95d3ca31db8774b3134f9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -117,6 +117,12 @@ Features:
   the seed from there already, if EFI_RNG_PROTOCOL is not implemented by
   firmware.
 
+* sd-boot: include domain specific hash string in hash function for random seed
+  plus sizes of everything. also include DMI/SMBIOS blob
+
+* accept a random seed via DMI/SMBIOS vendor string that is credited to the
+  kernel RNG, as cheap alternative to virtio-rng
+
 * sd-stub: invoke random seed logic the same way as in sd-boot, except if
   random seed EFI variable is already set. That way, the variable set will be
   set in all cases: if you just use sd-stub, or just sd-boot, or both.
@@ -1297,10 +1303,6 @@ Features:
 
 * fstab-generator: default to tmpfs-as-root if only usr= is specified on the kernel cmdline
 
-* initrd-parse-etc.service: can we skip daemon-reload if /sysroot/etc/fstab is missing?
-  Note that we start initrd-fs.target and initrd-cleanup.target there, so a straightforward
-  ConditionPathExists= is not enough.
-
 * docs: bring https://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date
 
 * add a job mode that will fail if a transaction would mean stopping
index 4ba37844696e4e3dd439bcfb5e757b00ea41fd91..f0d9865829f4b30c4e56739384d5c069d8e2a5c4 100644 (file)
@@ -266,7 +266,8 @@ services where they are ultimately consumed.
    three of these specific switches would set credential `foo` to `bar`.)
    Passing credentials via the SMBIOS mechanism is typically preferable over
    `fw_cfg` since it is faster and less specific to the chosen VMM
-   implementation.
+   implementation. Moreover, `fw_cfg` has a 55 character limitation
+   on names passed that way. So some settings may not fit.
 
 3. Credentials can also be passed into a system via the kernel command line,
    via the `systemd.set-credential=` kernel command line option. Note though
index 1c3f6b62bb1cabb7a53dd576597b1070ef74ebf7..a0f870bd0a50336fe835a8a8adfc823607e42ea9 100644 (file)
@@ -4,10 +4,13 @@
 #   60-sensor.rules
 #
 # Match string formats:
+# sensor:<label>:modalias:<parent modalias pattern>:dmi:<dmi pattern>
 # sensor:modalias:<parent modalias pattern>:dmi:<dmi pattern>
 #
 # The device modalias can be seen in the `modalias` file of the sensor parent,
+# and the device label can be seen in the `label` file of the sensor,
 # for example:
+#   cat /sys/`udevadm info -q path -n /dev/iio:device0`/label
 #   cat /sys/`udevadm info -q path -n /dev/iio:device0`/../modalias
 #
 # The full DMI string of the running machine can be read from
@@ -406,28 +409,20 @@ sensor:modalias:acpi:KXCJ9000*:dmi:*:bvrZY-8-BI-PX4S70VTR400-X423B-005-D:*:rvnAM
 #########################################
 # Google Chromebooks
 #########################################
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-
-# caroline board (Samsung Chromebook Pro) reports itself as svnGoogle
-sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
-# Dell Inspiron Chromebook 14 2-in-1
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnVayne*:*
+# CrOS EC & kernel drivers internally correct for per-board sensor orientations,
+# but they return values in the inverse direction (Android & W3C specs vs HID).
+sensor:modalias:platform:cros-ec-accel:*
+sensor:modalias:platform:cros-ec-accel-legacy:*
+sensor:accel-display:modalias:platform:cros-ec-accel:*
+sensor:accel-display:modalias:platform:cros-ec-accel-legacy:*
  ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
 
-# nocturne board (Google Pixel Slate)
-sensor:modalias:platform:cros-ec-accel:dmi:*Google_Nocturne*:*
- ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
-
-# rammus board (Asus Chromebook Flip C433)
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnRammus*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
-
-# Lenovo ThinkPad C13 Yoga
-sensor:modalias:platform:cros-ec-accel:dmi:*svnGoogle:pnMorphius*:*
- ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+# Base accel reports the same as display when lid angle is 180 degrees (vs 0),
+# so it needs an additional 180 degree rotation around the X axis.
+sensor:accel-base:modalias:platform:cros-ec-accel:*
+sensor:accel-base:modalias:platform:cros-ec-accel-legacy:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
 
 #########################################
 # GP-electronic
index 0a1911507a22e608e5d53f4bb1372200825195df..821ebcb1ca2f30a43b6b4fb7db0d7fb941f2ef60 100644 (file)
@@ -1,13 +1,21 @@
 # This file is part of systemd.
 #
 # Database for signal analyzers (protocol analyzers, logic analyzers,
-# oscilloscopes, multimeters, bench power supplies, etc.) that should
-# be accessible to the seat owner.
+# oscilloscopes, multimeters, bench power supplies, etc.) or just
+# anything that has to do with electronics and that should be
+# accessible to the seat owner.
 #
 # Permitted keys:
 #   Specify if a device is a signal analyzer
 #   ID_SIGNAL_ANALYZER=1|0
 
+###########################################################
+# Greaseweazle
+###########################################################
+# Greaseweazle
+usb:v1209p4D69*
+ ID_SIGNAL_ANALYZER=1
+
 ###########################################################
 # Total Phase
 ###########################################################
index 7bad559699b0e99789501cbc5762e1ec03dbb979..61932fb0185b766456ee3534424eccd7c5abca64 100755 (executable)
@@ -72,7 +72,20 @@ TYPES = {'mouse':    ('usb', 'bluetooth', 'ps2', '*'),
          'touchpad': ('i8042', 'rmi', 'bluetooth', 'usb'),
          'joystick': ('i8042', 'rmi', 'bluetooth', 'usb'),
          'keyboard': ('name', ),
-         'sensor':   ('modalias', ),
+         'sensor':   ('modalias',
+                      'accel-base',
+                      'accel-display',
+                      'accel-camera',
+                      'proximity-palmrest',
+                      'proximity-palmrest-left',
+                      'proximity-palmrest-right',
+                      'proximity-lap',
+                      'proximity-wifi',
+                      'proximity-lte',
+                      'proximity-wifi-lte',
+                      'proximity-wifi-left',
+                      'proximity-wifi-right',
+                      ),
          'ieee1394-unit-function' : ('node', ),
          'camera':   ('usb'),
         }
index 1664f68157a2adb0c2d1a39d70cd16484ef68976..85820ff6068243a92aa1e8fa5090e34d0f7d3dd0 100644 (file)
         <listitem><para>Install binaries for all supported EFI architectures (this implies <option>--no-variables</option>).</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--efi-boot-option-description=</option></term>
+        <listitem><para>Description of the entry added to the firmware's boot option list. Defaults to <literal>Linux
+        Boot Manager</literal>.</para>
+
+        <para>Using the default entry name <literal>Linux Boot Manager</literal> is generally preferable as only
+        one bootloader installed to a single ESP partition should be used to boot any number of OS installations
+        found on the various disks installed in the system. Specifically distributions should not use this flag
+        to install a branded entry in the boot option list. However in situations with multiple disks, each with
+        their own ESP partition, it can be beneficial to make it easier to identify the bootloader being used in
+        the firmware's boot option menu.</para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="no-pager"/>
       <xi:include href="standard-options.xml" xpointer="json" />
       <xi:include href="standard-options.xml" xpointer="help"/>
index b29e494ee99628a3b35d9141b356dbc7fbc6e7d5..6c69c8a9bd9a769bce61f1bacdc34bae88838937 100644 (file)
@@ -174,30 +174,30 @@ emergency.service    |              |              |
     available to the user.</para>
 
 <programlisting>
-    (various           (various         (various
-     timers...)         paths...)        sockets...)    (sound devices)
-         |                  |                 |               |
-         v                  v                 v               v
-   timers.target      paths.target     sockets.target    sound.target
-         |                  |                 |
-         \______________   _|_________________/         (bluetooth devices)
-                        \ /                                   |
-                         V                                    v
-                   basic.target                          bluetooth.target
-                         |
-              __________/ \_______                      (smartcard devices)
-             /                    \                           |
-             |                    |                           v
-             |                    v                      smartcard.target
-             v            graphical-session-pre.target
- (various user services)          |                       (printers)
-             |                    v                           |
-             |       (services for the graphical session)     v
-             |                    |                       printer.target
-             v                    v
-      <emphasis>default.target</emphasis>      graphical-session.target</programlisting>
-
 </refsect1>
+   (various           (various         (various
+    timers...)         paths...)        sockets...)    (sound devices)
+        |                  |                 |               |
+        v                  v                 v               v
+  timers.target      paths.target     sockets.target    sound.target
+        |                  |                 |
+        \______________   _|_________________/         (bluetooth devices)
+                       \ /                                   |
+                        V                                    v
+                  basic.target                          bluetooth.target
+                        |
+             __________/ \_______                      (smartcard devices)
+            /                    \                           |
+            |                    |                           v
+            |                    v                      smartcard.target
+            v            graphical-session-pre.target
+(various user services)          |                       (printers)
+            |                    v                           |
+            |       (services for the graphical session)     v
+            |                    |                       printer.target
+            v                    v
+     <emphasis>default.target</emphasis>      graphical-session.target</programlisting>
+
+ </refsect1>
 
   <refsect1>
     <title>Bootup in the Initial RAM Disk (initrd)</title>
@@ -239,59 +239,59 @@ emergency.service    |              |              |
     <filename>/sysroot</filename>.
     </para>
 
-<programlisting>                                               : (beginning identical to above)
-                                               :
-                                               v
-                                         basic.target
-                                               |                                 emergency.service
-                        ______________________/|                                         |
-                       /                       |                                         v
-                       |            initrd-root-device.target                    <emphasis>emergency.target</emphasis>
-                       |                       |
-                       |                       v
-                       |                  sysroot.mount
-                       |                       |
-                       |                       v
-                       |             initrd-root-fs.target
-                       |                       |
-                       |                       v
-                       v            initrd-parse-etc.service
-                (custom initrd                 |
                services...)                  v
-                       |            (sysroot-usr.mount and
-                       |             various mounts marked
-                       |               with fstab option
-                       |              x-initrd.mount...)
-                       |                       |
-                       |                       v
-                       |                initrd-fs.target
-                       \______________________ |
-                                              \|
-                                               v
-                                          initrd.target
-                                               |
-                                               v
-                                     initrd-cleanup.service
-                                          isolates to
-                                    initrd-switch-root.target
-                                               |
-                                               v
-                        ______________________/|
-                       /                       v
-                       |        initrd-udevadm-cleanup-db.service
-                       v                       |
-                (custom initrd                 |
                services...)                  |
-                       \______________________ |
-                                              \|
-                                               v
-                                   initrd-switch-root.target
-                                               |
-                                               v
-                                   initrd-switch-root.service
-                                               |
-                                               v
-                                     Transition to Host OS</programlisting>
+<programlisting>                               : (beginning identical to above)
+                               :
+                               v
+                         basic.target
+                               |                       emergency.service
+        ______________________/|                               |
+       /                       |                               v
+       |            initrd-root-device.target          <emphasis>emergency.target</emphasis>
+       |                       |
+       |                       v
+       |                  sysroot.mount
+       |                       |
+       |                       v
+       |             initrd-root-fs.target
+       |                       |
+       |                       v
+       v            initrd-parse-etc.service
+(custom initrd                 |
+ services...)                  v
+       |            (sysroot-usr.mount and
+       |             various mounts marked
+       |               with fstab option
+       |              x-initrd.mount...)
+       |                       |
+       |                       v
+       |                initrd-fs.target
+       \______________________ |
+                              \|
+                               v
+                          initrd.target
+                               |
+                               v
+                     initrd-cleanup.service
+                          isolates to
+                    initrd-switch-root.target
+                               |
+                               v
+        ______________________/|
+       /                       v
+       |        initrd-udevadm-cleanup-db.service
+       v                       |
+(custom initrd                 |
+ services...)                  |
+       \______________________ |
+                              \|
+                               v
+                   initrd-switch-root.target
+                               |
+                               v
+                   initrd-switch-root.service
+                               |
+                               v
+                     Transition to Host OS</programlisting>
   </refsect1>
 
   <refsect1>
@@ -300,33 +300,40 @@ emergency.service    |              |              |
     <para>System shutdown with systemd also consists of various target
     units with some minimal ordering structure applied:</para>
 
-<programlisting>                                  (conflicts with  (conflicts with
-                                    all system     all file system
-                                     services)     mounts, swaps,
-                                         |           cryptsetup/
-                                         |           veritysetup
-                                         |          devices, ...)
-                                         |                |
-                                         v                v
-                                  shutdown.target    umount.target
-                                         |                |
-                                         \_______   ______/
-                                                 \ /
-                                                  v
-                                         (various low-level
-                                              services)
-                                                  |
-                                                  v
-                                            final.target
-                                                  |
-            _____________________________________/ \_________________________________
-           /                         |                        |                      \
-           |                         |                        |                      |
-           v                         v                        v                      v
-systemd-reboot.service   systemd-poweroff.service   systemd-halt.service   systemd-kexec.service
-           |                         |                        |                      |
-           v                         v                        v                      v
-    <emphasis>reboot.target</emphasis>             <emphasis>poweroff.target</emphasis>            <emphasis>halt.target</emphasis>           <emphasis>kexec.target</emphasis></programlisting>
+<programlisting>                       (conflicts with  (conflicts with
+                          all system     all file system
+                           services)     mounts, swaps,
+                               |           cryptsetup/
+                               |           veritysetup
+                               |          devices, ...)
+                               |                |
+                               v                v
+                        shutdown.target    umount.target
+                               |                |
+                               \_______   ______/
+                                       \ /
+                                        v
+                               (various low-level
+                                    services)
+                                        |
+                                        v
+                                  final.target
+                                        |
+            ___________________________/ \_________________
+           /               |               |               \
+           |               |               |               |
+           v               |               |               |
+systemd-reboot.service     |               |               |
+           |               v               |               |
+           |    systemd-poweroff.service   |               |
+           v               |               v               |
+     <emphasis>reboot.target</emphasis>         |      systemd-halt.service     |
+                           v               |               v
+                   <emphasis>poweroff.target</emphasis>         |    systemd-kexec.service
+                                           v               |
+                                      <emphasis>halt.target</emphasis>          |
+                                                           v
+                                                     <emphasis>kexec.target</emphasis></programlisting>
 
     <para>Commonly used system shutdown targets are <emphasis>emphasized</emphasis>.</para>
 
index 22411166a8dfe31b7b24a684ff944a38b1068dac..a296949595ec47fce822d02b7d697deb604248db 100644 (file)
         <term><option>keyfile-timeout=</option></term>
 
         <listitem><para> Specifies the timeout for the device on
-        which the key file resides and falls back to a password if
-        it could not be mounted. See
+        which the key file resides or the device used as the key file,
+        and falls back to a password if it could not be accessed. See
         <citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         for key files on external devices.
         </para></listitem>
index 838eb6738d8d3645b5dec24d5fa8a55069513e20..c6b8c7fb3d65fea3d156e370cfbc149d0f129c75 100644 (file)
@@ -39,6 +39,9 @@ node /org/freedesktop/oom1 {
   interface org.freedesktop.oom1.Manager {
     methods:
       DumpByFileDescriptor(out h fd);
+    signals:
+      Killed(s cgroup,
+             s reason);
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -56,12 +59,38 @@ node /org/freedesktop/oom1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="DumpByFileDescriptor()"/>
 
+    <variablelist class="dbus-signal" generated="True" extra-ref="Killed"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
       <title>Methods</title>
 
-      <para>...</para>
+      <para><function>Killed</function> signal is sent when any cgroup is killed by oomd.</para>
+      <para>Note that more reasons will be added in the future, and the table below will be expanded accordingly.</para>
+      <table>
+        <title>Killing reasons</title>
+        <tgroup cols="2" align="left" colsep="1" rowsep="1">
+        <colspec colname="reason"/>
+        <colspec colname="description"/>
+        <thead>
+          <row>
+            <entry>Reason</entry>
+            <entry>Description</entry>
+          </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry>memory-used</entry>
+            <entry>Application took too much memory and swap.</entry>
+          </row>
+          <row>
+            <entry>memory-pressure</entry>
+            <entry>Application took enough memory and swap to cause sufficient slowdown of other applications.</entry>
+          </row>
+        </tbody>
+        </tgroup>
+      </table>
     </refsect2>
   </refsect1>
 
index f821d6562a64bfe075a089994fee9a25d7532f9f..120ffbc8ef08edd43ab0d37f2f4416057f2285ae 100644 (file)
@@ -426,6 +426,8 @@ node /org/freedesktop/systemd1 {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly t DefaultTimeoutAbortUSec = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly t DefaultDeviceTimeoutUSec = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t DefaultRestartUSec = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly t DefaultStartLimitIntervalUSec = ...;
@@ -674,6 +676,8 @@ node /org/freedesktop/systemd1 {
 
     <!--property DefaultTimeoutAbortUSec is not documented!-->
 
+    <!--property DefaultDeviceTimeoutUSec is not documented!-->
+
     <!--property DefaultRestartUSec is not documented!-->
 
     <!--property DefaultStartLimitIntervalUSec is not documented!-->
@@ -1082,6 +1086,8 @@ node /org/freedesktop/systemd1 {
 
     <variablelist class="dbus-property" generated="True" extra-ref="DefaultTimeoutAbortUSec"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="DefaultDeviceTimeoutUSec"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="DefaultRestartUSec"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="DefaultStartLimitIntervalUSec"/>
index fc880c47651499a77be7b37461795af9d0bad053..168c1675a9491d63a87d09ab98c06ea4c996d420 100644 (file)
           determines the fallback hostname.</para></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><varname>ARCHITECTURE=</varname></term>
+          <listitem><para>A string that specifies which CPU architecture the userspace binaries require.
+          The architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
+          described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+          The field is optional and should only be used when just single architecture is supported.
+          It may provide redundant information when used in a GPT partition with a GUID type that already
+          encodes the architecture. If this is not the case, the architecture should be specified in
+          e.g., an extension image, to prevent an incompatible host from loading it.
+          </para></listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><varname>SYSEXT_LEVEL=</varname></term>
 
index 2aa396e3004bfe4790b5b166b0063e512e334d06..afde0fad7e2575e6fe6d3bd17983b017e0e4b992 100644 (file)
         </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--unlock-key-file=</option><replaceable>PATH</replaceable></term>
+
+        <listitem><para>Use a file instead of a password/passphrase read from stdin to unlock the volume.
+        Expects the PATH to the file containing your key to unlock the volume. Currently there is nothing like
+        <option>--key-file-offset=</option> or <option>--key-file-size=</option> so this file has to only
+        contain the full key.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--pkcs11-token-uri=</option><replaceable>URI</replaceable></term>
 
index 380ba57884a3da0e03230c2b4713f7d6c1e932f2..c34244d14a7e0ff3df2590698f6b587ccd4bd30f 100644 (file)
@@ -71,7 +71,9 @@
 
     <orderedlist>
       <listitem><para>The <filename>repart.d/*.conf</filename> configuration files are loaded and parsed,
-      and ordered by filename (without the directory prefix).</para></listitem>
+      and ordered by filename (without the directory prefix). For each configuration file,
+      drop-in files are looked for in directories with same name as the configuration file
+      with a suffix ".d" added.</para></listitem>
 
       <listitem><para>The partition table already existing on the block device is loaded and
       parsed.</para></listitem>
         <listitem><para>Takes a file system path. If specified the <filename>*.conf</filename> files are read
         from the specified directory instead of searching in <filename>/usr/lib/repart.d/*.conf</filename>,
         <filename>/etc/repart.d/*.conf</filename>,
-        <filename>/run/repart.d/*.conf</filename>.</para></listitem>
+        <filename>/run/repart.d/*.conf</filename>.</para>
+
+        <para>This parameter can be specified multiple times.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 42e8e12df97ff660c39d4f6171291067f5a21c6b..f4dd150a538eb62da08f11d2eabf0e47de23d113 100644 (file)
     accessed.</para>
 
     <para>Note that there is no concept of enabling/disabling installed system extension images: all
-    installed extension images are automatically activated at boot. However, you can place a symlink
-    to <filename>/dev/null</filename> in <filename>/etc/extensions/</filename> to "mask" an image with
-    the same name in a folder with lower precedence.</para>
+    installed extension images are automatically activated at boot. However, you can place an empty directory
+    named like the extension (no <filename>.raw</filename>) in <filename>/etc/extensions/</filename> to "mask"
+    an extension with the same name in a system folder with lower precedence.</para>
 
     <para>A simple mechanism for version compatibility is enforced: a system extension image must carry a
     <filename>/usr/lib/extension-release.d/extension-release.<replaceable>$name</replaceable></filename>
     file, which must match its image name, that is compared with the host <filename>os-release</filename>
-    file: the contained <varname>ID=</varname> fields have to match, as well as the
-    <varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined, the
-    <varname>VERSION_ID=</varname> field has to match instead. System extensions should not ship a
-    <filename>/usr/lib/os-release</filename> file (as that would be merged into the host
-    <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable). The
-    <filename>extension-release</filename> file follows the same format and semantics, and carries the same
+    file: the contained <varname>ID=</varname> fields have to match unless <literal>_any</literal> is set
+    for the extension. If the extension <varname>ID=</varname> is not <literal>_any</literal>, the
+    <varname>SYSEXT_LEVEL=</varname> field (if defined) has to match. If the latter is not defined, the
+    <varname>VERSION_ID=</varname> field has to match instead. If the extension defines the
+    <varname>ARCHITECTURE=</varname> field and the value is not <literal>_any</literal> it has to match the kernel's
+    architecture reported by <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+    but the used architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
+    described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    System extensions should not ship a <filename>/usr/lib/os-release</filename> file (as that would be merged
+    into the host <filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable).
+    The <filename>extension-release</filename> file follows the same format and semantics, and carries the same
     content, as the <filename>os-release</filename> file of the OS, but it describes the resources carried
     in the extension image.</para>
   </refsect1>
index ef311f1971fbb046b04ccee337f8894a4b0f1127..065bbd5a647091f4f3f80bf64398667c19a435b8 100644 (file)
         100ms.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>DefaultDeviceTimeoutSec=</varname></term>
+
+        <listitem><para>Configures the default timeout for waiting for devices. It can be changed per
+        device via the <varname>x-systemd.device-timeout=</varname> option in <filename>/etc/fstab</filename>
+        and <filename>/etc/crypttab</filename> (see
+        <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+        Defaults to 90s.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>DefaultStartLimitIntervalSec=</varname></term>
         <term><varname>DefaultStartLimitBurst=</varname></term>
index e5a3d7a3139dad6bf7bb888f2435ee820d2fadff..8aac42b49de13a1abf4421cfc5c2d7bbd675b349 100644 (file)
     <variablelist>
         <varlistentry>
           <term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></varname></term>
+          <term><varname>ID_NET_NAME_ONBOARD=<replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></varname></term>
 
           <listitem><para>This name is set based on the numeric ordering information given by the firmware
-          for on-board devices. The name consists of the prefix, letter <constant>o</constant>, and a number
-          specified by the firmware. This is only available for PCI devices.</para>
+          for on-board devices. Different schemes are used depending on the firmware type, as described in the table below.</para>
+
+            <table>
+              <title>Onboard naming schemes</title>
+
+              <tgroup cols='2'>
+                <thead>
+                  <row>
+                    <entry>Format</entry>
+                    <entry>Description</entry>
+                  </row>
+                </thead>
+
+                <tbody>
+                  <row>
+                    <entry><replaceable>prefix</replaceable><constant>o</constant><replaceable>number</replaceable></entry>
+                    <entry>PCI onboard index</entry>
+                  </row>
+
+                  <row>
+                    <entry><replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></entry>
+                    <entry>Devicetree alias index</entry>
+                  </row>
+
+                </tbody>
+              </tgroup>
+            </table>
           </listitem>
         </varlistentry>
 
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><constant>v252</constant></term>
+
+          <listitem><para>Added naming scheme for platform devices with devicetree aliases.</para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
 
     <para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
index 94c9308e46ab9de9c10673335d1646a9ba9f1fcf..266ad52df28d1de4261caf6dbe6db7519a8d3d47 100644 (file)
         <filename>/dev/net/tun</filename> device.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>KeepCarrier=</varname></term>
+        <listitem>
+          <para>Takes a boolean. If enabled, to make the interface maintain its carrier status, the file
+          descriptor of the interface is kept open. This may be useful to keep the interface in running
+          state, for example while the backing process is temporarily shutdown. Defaults to
+          <literal>no</literal>.</para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 2b545e4d9316f97d07936b6293d27a637b223647..c16eb3951a18cf806562415397c492d29af21443 100644 (file)
         <term><varname>StartupCPUWeight=<replaceable>weight</replaceable></varname></term>
 
         <listitem>
-          <para>Assign the specified CPU time weight to the processes executed, if the unified control group
-          hierarchy is used on the system. These options take an integer value and control the
-          <literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
-          100. For details about this control group attribute, see <ulink
-          url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
-          and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
-          Scheduler</ulink>.  The available CPU time is split up among all units within one slice relative to
-          their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
+          <para>These options accept an integer value or a the special string "idle":</para>
+            <itemizedlist>
+              <listitem>
+                <para>If set to an integer value, assign the specified CPU time weight to the processes executed,
+                if the unified control group hierarchy is used on the system. These options control the
+                <literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
+                100. For details about this control group attribute, see <ulink
+                url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
+                and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
+                Scheduler</ulink>.  The available CPU time is split up among all units within one slice relative to
+                their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
+              </listitem>
+              <listitem>
+                <para>If set to the special string "idle", mark the cgroup for "idle scheduling", which means
+                that it will get CPU resources only when there are no processes not marked in this way to execute in this
+                cgroup or its siblings. This setting corresponds to the <literal>cpu.idle</literal> cgroup attribute.</para>
+
+                <para>Note that this value only has an effect on cgroup-v2, for cgroup-v1 it is equivalent to the minimum weight.</para>
+              </listitem>
+            </itemizedlist>
 
           <para>While <varname>StartupCPUWeight=</varname> applies to the startup and shutdown phases of the system,
           <varname>CPUWeight=</varname> applies to normal runtime of the system, and if the former is not set also to
index cf3aa2b4964976493e86a5985a7602d57467df19..aa2ae27a93d96dbcc319bcb642d569e86a6c8d99 100644 (file)
@@ -393,7 +393,7 @@ possible_common_cc_flags = [
 c_args = get_option('c_args')
 
 # Our json library does not support -ffinite-math-only, which is enabled by -Ofast or -ffast-math.
-if (('-Ofast' in c_args or '-ffast-math' in c_args or '-ffinite-math-only' in c_args) and not ('-fno-finite-math-only' in c_args))
+if (('-Ofast' in c_args or '-ffast-math' in c_args or '-ffinite-math-only' in c_args) and '-fno-finite-math-only' not in c_args)
         error('-Ofast, -ffast-math, or -ffinite-math-only is specified in c_args.')
 endif
 
@@ -2324,6 +2324,10 @@ exe = executable(
         install : true,
         install_dir : systemgeneratordir)
 
+meson.add_install_script(meson_make_symlink,
+                         systemgeneratordir / 'systemd-fstab-generator',
+                         rootlibexecdir / 'systemd-sysroot-fstab-check')
+
 if want_tests != 'false'
         test('test-fstab-generator',
              test_fstab_generator_sh,
index 58b84cae98b814f8d6366bd0cf770e1b0c804f84..8efd1e97fa3265c1599fb2b5936e531671089c75 100644 (file)
@@ -8,11 +8,11 @@ Bootable=yes
 HostonlyInitrd=yes
 # Prevent ASAN warnings when building the image
 Environment=ASAN_OPTIONS=verify_asan_link_order=false
+OutputDirectory=mkosi.output
 
 [Content]
 BuildDirectory=mkosi.builddir
 Cache=mkosi.cache
-InstallDirectory=mkosi.installdir
 SourceFileTransferFinal=copy-git-others
 
 [Host]
index 5044f4ded1ec809cc9d9c4626824819ef6a1e0e1..c6b4acd7ac682aae9568333fbece274ad2335326 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -5,19 +5,21 @@
 #
 # Gabor Kelemen <kelemeng at gnome dot hu>, 2015, 2016.
 # Balázs Úr <urbalazs at gmail dot com>, 2016.
+# Balázs Meskó <meskobalazs@mailbox.org>, 2022.
 msgid ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2021-01-08 17:48+0100\n"
-"PO-Revision-Date: 2016-08-23 18:03+0100\n"
-"Last-Translator: Balázs Úr <urbalazs@gmail.com>\n"
-"Language-Team: Hungarian <openscope at googlegroups dot com>\n"
+"PO-Revision-Date: 2022-08-09 20:19+0000\n"
+"Last-Translator: Balázs Meskó <meskobalazs@mailbox.org>\n"
+"Language-Team: Hungarian <https://translate.fedoraproject.org/projects/"
+"systemd/master/hu/>\n"
 "Language: hu\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Lokalize 2.0\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.13\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -71,73 +73,57 @@ msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
 
 #: src/home/org.freedesktop.home1.policy:13
 msgid "Create a home area"
-msgstr ""
+msgstr "Saját terület létrehozása"
 
 #: src/home/org.freedesktop.home1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to create a user's home area."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a felhasználó saját területének létrehozásához."
 
 #: src/home/org.freedesktop.home1.policy:23
 msgid "Remove a home area"
-msgstr ""
+msgstr "Saját terület eltávolítása"
 
 #: src/home/org.freedesktop.home1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to remove a user's home area."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a felhasználó saját területének eltávolításához."
 
 #: src/home/org.freedesktop.home1.policy:33
 msgid "Check credentials of a home area"
-msgstr ""
+msgstr "Saját terület hitelesítő adatainak ellenőrzése"
 
 #: src/home/org.freedesktop.home1.policy:34
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
 msgid ""
 "Authentication is required to check credentials against a user's home area."
 msgstr ""
-"Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások "
-"kezeléséhez."
+"Hitelesítés szükséges a hitelesítő adatok a felhasználó saját területével "
+"való összevetéséhez."
 
 #: src/home/org.freedesktop.home1.policy:43
 msgid "Update a home area"
-msgstr ""
+msgstr "Saját terület frissítése"
 
 #: src/home/org.freedesktop.home1.policy:44
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
 msgid "Authentication is required to update a user's home area."
-msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+msgstr "Hitelesítés szükséges a felhasználó saját területének frissítéséhez."
 
 #: src/home/org.freedesktop.home1.policy:53
 msgid "Resize a home area"
-msgstr ""
+msgstr "Saját terület átméretezése"
 
 #: src/home/org.freedesktop.home1.policy:54
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to resize a user's home area."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a felhasználó saját területének átméretezéséhez."
 
 #: src/home/org.freedesktop.home1.policy:63
 msgid "Change password of a home area"
-msgstr ""
+msgstr "Saját terület hitelesítő adatainak módosítása"
 
 #: src/home/org.freedesktop.home1.policy:64
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to manage active sessions, users and seats."
 msgid ""
 "Authentication is required to change the password of a user's home area."
 msgstr ""
-"Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások "
-"kezeléséhez."
+"Hitelesítés szükséges a felhasználó saját területének jelszavának "
+"módosításához."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
 msgid "Set hostname"
@@ -165,45 +151,43 @@ msgstr "Gépinformációk beállítása"
 
 #: src/hostname/org.freedesktop.hostname1.policy:42
 msgid "Authentication is required to set local machine information."
-msgstr "Hitelesítés szükséges a helyi gép információinak beállításához."
+msgstr "Hitelesítés szükséges a helyi gépinformációk beállításához."
 
 #: src/hostname/org.freedesktop.hostname1.policy:51
 msgid "Get product UUID"
-msgstr ""
+msgstr "Termék UUID-jának lekérése"
 
 #: src/hostname/org.freedesktop.hostname1.policy:52
-#, fuzzy
-#| msgid "Authentication is required to reload '$(unit)'."
 msgid "Authentication is required to get product UUID."
-msgstr "Hitelesítés szükséges a következő újratöltéséhez: „$(unit)”."
+msgstr "Hitelesítés szükséges a termék UUID-jának lekéréséhez."
 
 #: src/import/org.freedesktop.import1.policy:22
 msgid "Import a VM or container image"
-msgstr "VM vagy konténer lemezkép importálása"
+msgstr "VM vagy konténer lemezképének importálása"
 
 #: src/import/org.freedesktop.import1.policy:23
 msgid "Authentication is required to import a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép importálásához."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének importálásához"
 
 #: src/import/org.freedesktop.import1.policy:32
 msgid "Export a VM or container image"
-msgstr "VM vagy konténer lemezkép exportálása"
+msgstr "VM vagy konténer lemezképének exportálása"
 
 #: src/import/org.freedesktop.import1.policy:33
 msgid "Authentication is required to export a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép exportálásához."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének exportálásához"
 
 #: src/import/org.freedesktop.import1.policy:42
 msgid "Download a VM or container image"
-msgstr "VM vagy konténer lemezkép letöltése"
+msgstr "VM vagy konténer lemezképének letöltése"
 
 #: src/import/org.freedesktop.import1.policy:43
 msgid "Authentication is required to download a VM or container image"
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép letöltéséhez."
+msgstr "Hitelesítés szükséges a VM vagy konténer lemezképének letöltéséhez"
 
 #: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
-msgstr "Területi beállítás megadása"
+msgstr "Rendszer területi beállításának megadása"
 
 #: src/locale/org.freedesktop.locale1.policy:23
 msgid "Authentication is required to set the system locale."
@@ -211,7 +195,7 @@ msgstr "Hitelesítés szükséges a rendszer területi beállításainak megadá
 
 #: src/locale/org.freedesktop.locale1.policy:33
 msgid "Set system keyboard settings"
-msgstr "Rendszer billentyűzetbeállítások megadása"
+msgstr "Rendszer billentyűzetbeállításainak megadása"
 
 #: src/locale/org.freedesktop.locale1.policy:34
 msgid "Authentication is required to set the system keyboard settings."
@@ -220,7 +204,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:22
 msgid "Allow applications to inhibit system shutdown"
-msgstr "Alkalmazások meggátolhatják a rendszer leállítását"
+msgstr "Az alkalmazások meggátolhatják a rendszer leállítását"
 
 #: src/login/org.freedesktop.login1.policy:23
 msgid ""
@@ -231,7 +215,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:33
 msgid "Allow applications to delay system shutdown"
-msgstr "Alkalmazások késleltethetik a rendszer leállítását"
+msgstr "Az alkalmazások késleltethetik a rendszer leállítását"
 
 #: src/login/org.freedesktop.login1.policy:34
 msgid "Authentication is required for an application to delay system shutdown."
@@ -241,7 +225,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:44
 msgid "Allow applications to inhibit system sleep"
-msgstr "Alkalmazások meggátolhatják a rendszer altatását"
+msgstr "Az alkalmazások meggátolhatják a rendszer altatását"
 
 #: src/login/org.freedesktop.login1.policy:45
 msgid "Authentication is required for an application to inhibit system sleep."
@@ -250,7 +234,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:55
 msgid "Allow applications to delay system sleep"
-msgstr "Alkalmazások késleltethetik a rendszer altatását"
+msgstr "Az alkalmazások késleltethetik a rendszer altatását"
 
 #: src/login/org.freedesktop.login1.policy:56
 msgid "Authentication is required for an application to delay system sleep."
@@ -260,7 +244,7 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:65
 msgid "Allow applications to inhibit automatic system suspend"
-msgstr "Alkalmazások meggátolhatják a rendszer automatikus felfüggesztését"
+msgstr "Az alkalmazások meggátolhatják a rendszer automatikus felfüggesztését"
 
 #: src/login/org.freedesktop.login1.policy:66
 msgid ""
@@ -273,7 +257,7 @@ msgstr ""
 #: src/login/org.freedesktop.login1.policy:75
 msgid "Allow applications to inhibit system handling of the power key"
 msgstr ""
-"Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
 
 #: src/login/org.freedesktop.login1.policy:76
 msgid ""
@@ -286,7 +270,7 @@ msgstr ""
 #: src/login/org.freedesktop.login1.policy:86
 msgid "Allow applications to inhibit system handling of the suspend key"
 msgstr ""
-"Alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését"
 
 #: src/login/org.freedesktop.login1.policy:87
 msgid ""
@@ -299,7 +283,7 @@ msgstr ""
 #: src/login/org.freedesktop.login1.policy:97
 msgid "Allow applications to inhibit system handling of the hibernate key"
 msgstr ""
-"Alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését"
 
 #: src/login/org.freedesktop.login1.policy:98
 msgid ""
@@ -311,7 +295,8 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:107
 msgid "Allow applications to inhibit system handling of the lid switch"
-msgstr "Alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését"
+msgstr ""
+"Az alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését"
 
 #: src/login/org.freedesktop.login1.policy:108
 msgid ""
@@ -322,22 +307,16 @@ msgstr ""
 "kezelésének meggátlásához."
 
 #: src/login/org.freedesktop.login1.policy:117
-#, fuzzy
-#| msgid "Allow applications to inhibit system handling of the power key"
 msgid "Allow applications to inhibit system handling of the reboot key"
 msgstr ""
-"Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését"
+"Az alkalmazások meggátolhatják az újraindítás gomb rendszer általi kezelését"
 
 #: src/login/org.freedesktop.login1.policy:118
-#, fuzzy
-#| msgid ""
-#| "Authentication is required for an application to inhibit system handling "
-#| "of the power key."
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the reboot key."
 msgstr ""
-"Hitelesítés szükséges egy alkalmazás számára a bekapcsoló gomb rendszer "
+"Hitelesítés szükséges egy alkalmazás számára az újraindítás gomb rendszer "
 "általi kezelésének meggátlásához."
 
 #: src/login/org.freedesktop.login1.policy:128
@@ -347,8 +326,8 @@ msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználó szám
 #: src/login/org.freedesktop.login1.policy:129
 msgid "Explicit request is required to run programs as a non-logged-in user."
 msgstr ""
-"Határozott kérés szükséges a programfuttatáshoz be nem jelentkezett "
-"felhasználóként."
+"Határozott kérés szükséges a be nem jelentkezett felhasználókénti "
+"programfuttatáshoz."
 
 #: src/login/org.freedesktop.login1.policy:138
 msgid "Allow non-logged-in users to run programs"
@@ -357,18 +336,18 @@ msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználók szá
 #: src/login/org.freedesktop.login1.policy:139
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
-"Hitelesítés szükséges a programfuttatáshoz be nem jelentkezett "
-"felhasználóként."
+"Hitelesítés szükséges a be nem jelentkezett felhasználókénti "
+"programfuttatáshoz."
 
 #: src/login/org.freedesktop.login1.policy:148
 msgid "Allow attaching devices to seats"
-msgstr "Eszközök csatolásának engedélyezése munkaállomásokhoz"
+msgstr "Eszközök munkaállomásokhoz csatolásának engedélyezése"
 
 #: src/login/org.freedesktop.login1.policy:149
 msgid "Authentication is required to attach a device to a seat."
 msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+"Hitelesítés szükséges az eszköz munkaállomáshoz csatolásának "
+"engedélyezéséhez."
 
 #: src/login/org.freedesktop.login1.policy:159
 msgid "Flush device to seat attachments"
@@ -424,7 +403,7 @@ msgstr "Hitelesítés szükséges a rendszer újraindításához."
 
 #: src/login/org.freedesktop.login1.policy:213
 msgid "Reboot the system while other users are logged in"
-msgstr "A rendszer újraindítása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer újraindítása miközben be vannak jelentkezve más felhasználók"
 
 #: src/login/org.freedesktop.login1.policy:214
 msgid ""
@@ -448,52 +427,36 @@ msgstr ""
 "ennek meggátlását kérte."
 
 #: src/login/org.freedesktop.login1.policy:235
-#, fuzzy
-#| msgid "Hibernate the system"
 msgid "Halt the system"
-msgstr "A rendszer hibernálása"
+msgstr "A rendszer leállítása"
 
 #: src/login/org.freedesktop.login1.policy:236
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to halt the system."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges a rendszer leállításához."
 
 #: src/login/org.freedesktop.login1.policy:246
-#, fuzzy
-#| msgid "Hibernate the system while other users are logged in"
 msgid "Halt the system while other users are logged in"
-msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer leállítása miközben más felhasználók be vannak jelentkezve"
 
 #: src/login/org.freedesktop.login1.policy:247
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while other users are "
-#| "logged in."
 msgid ""
 "Authentication is required to halt the system while other users are logged "
 "in."
 msgstr ""
-"Hitelesítés szükséges a rendszer hibernálásához miközben be vannak "
-"jelentkezve más felhasználók."
+"Hitelesítés szükséges a rendszer leállításához miközben más felhasználók be "
+"vannak jelentkezve."
 
 #: src/login/org.freedesktop.login1.policy:257
-#, fuzzy
-#| msgid "Hibernate the system while an application is inhibiting this"
 msgid "Halt the system while an application is inhibiting this"
-msgstr "A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte"
+msgstr "A rendszer leállítása miközben egy alkalmazás ennek meggátlását kérte"
 
 #: src/login/org.freedesktop.login1.policy:258
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to hibernate the system while an application "
-#| "is inhibiting this."
 msgid ""
 "Authentication is required to halt the system while an application is "
 "inhibiting this."
 msgstr ""
-"Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás "
-"ennek meggátlását kérte."
+"Hitelesítés szükséges a rendszer leállításához miközben egy alkalmazás ennek "
+"meggátlását kérte."
 
 #: src/login/org.freedesktop.login1.policy:268
 msgid "Suspend the system"
@@ -539,7 +502,7 @@ msgstr "Hitelesítés szükséges a rendszer hibernálásához."
 
 #: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while other users are logged in"
-msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók"
+msgstr "A rendszer hibernálása miközben be vannak jelentkezve más felhasználók"
 
 #: src/login/org.freedesktop.login1.policy:311
 msgid ""
@@ -582,59 +545,55 @@ msgstr ""
 
 #: src/login/org.freedesktop.login1.policy:352
 msgid "Set the reboot \"reason\" in the kernel"
-msgstr ""
+msgstr "Az újraindítás „okának” beállítása a kernelben"
 
 #: src/login/org.freedesktop.login1.policy:353
-#, fuzzy
-#| msgid "Authentication is required to set the system timezone."
 msgid "Authentication is required to set the reboot \"reason\" in the kernel."
-msgstr "Hitelesítés szükséges a rendszer időzónájának beállításához."
+msgstr ""
+"Hitelesítés szükséges a rendszer újraindítási „okának” beállításához a "
+"kernelben."
 
 #: src/login/org.freedesktop.login1.policy:363
-#, fuzzy
-#| msgid "Allow indication to the firmware to boot to setup interface"
 msgid "Indicate to the firmware to boot to setup interface"
-msgstr "A firmware-nek jelezhető, hogy a beállítófelületet bootolja"
+msgstr ""
+"Jelzés a firmware számára, hogy a beállítófelületet indítsa el "
+"rendszerindításkor"
 
 #: src/login/org.freedesktop.login1.policy:364
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
 msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a firmware a beállítófelületet indítsa el "
+"rendszerindításkor."
 
 #: src/login/org.freedesktop.login1.policy:374
 msgid "Indicate to the boot loader to boot to the boot loader menu"
 msgstr ""
+"Jelzés a rendszerbetöltő számára, hogy a rendszerbetöltő menüt indítsa el "
+"rendszerindításkor"
 
 #: src/login/org.freedesktop.login1.policy:375
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
 msgid ""
 "Authentication is required to indicate to the boot loader to boot to the "
 "boot loader menu."
 msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a firmware a rendszerbetöltő menüt indítsa el "
+"rendszerindításkor."
 
 #: src/login/org.freedesktop.login1.policy:385
 msgid "Indicate to the boot loader to boot a specific entry"
 msgstr ""
+"Jelzés a rendszerbetöltő számára, hogy egy adott bejegyzést indítson el "
+"rendszerindításkor"
 
 #: src/login/org.freedesktop.login1.policy:386
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to indicate to the firmware to boot to setup "
-#| "interface."
 msgid ""
 "Authentication is required to indicate to the boot loader to boot into a "
 "specific boot loader entry."
 msgstr ""
-"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet "
-"bootolja"
+"Hitelesítés szükséges, hogy a rendszerbetöltő egy adott bejegyzést indítson "
+"el rendszerindításkor."
 
 #: src/login/org.freedesktop.login1.policy:396
 msgid "Set a wall message"
@@ -646,13 +605,11 @@ msgstr "Hitelesítés szükséges a falüzenet beállításához"
 
 #: src/login/org.freedesktop.login1.policy:406
 msgid "Change Session"
-msgstr ""
+msgstr "Munkamenet módosítása"
 
 #: src/login/org.freedesktop.login1.policy:407
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to change the virtual terminal."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr "Hitelesítés szükséges a virtuális terminál módosításához."
 
 #: src/machine/org.freedesktop.machine1.policy:22
 msgid "Log into a local container"
@@ -660,7 +617,7 @@ msgstr "Bejelentkezés helyi konténerbe"
 
 #: src/machine/org.freedesktop.machine1.policy:23
 msgid "Authentication is required to log into a local container."
-msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe."
+msgstr "Hitelesítés szükséges a helyi konténerbe történő bejelentkezéshez."
 
 #: src/machine/org.freedesktop.machine1.policy:32
 msgid "Log into the local host"
@@ -668,7 +625,7 @@ msgstr "Bejelentkezés a helyi gépre"
 
 #: src/machine/org.freedesktop.machine1.policy:33
 msgid "Authentication is required to log into the local host."
-msgstr "Hitelesítés szükséges a bejelentkezéshez a helyi gépre."
+msgstr "Hitelesítés szükséges a helyi gépre történtő bejelentkezéshez."
 
 #: src/machine/org.freedesktop.machine1.policy:42
 msgid "Acquire a shell in a local container"
@@ -714,246 +671,210 @@ msgstr "Hitelesítés szükséges helyi virtuális gépek és konténerek kezel
 
 #: src/machine/org.freedesktop.machine1.policy:95
 msgid "Manage local virtual machine and container images"
-msgstr "Helyi virtuális gép és konténer lemezképek kezelése"
+msgstr "Helyi virtuális gépek és konténerek lemezképeinek kezelése"
 
 #: src/machine/org.freedesktop.machine1.policy:96
 msgid ""
 "Authentication is required to manage local virtual machine and container "
 "images."
 msgstr ""
-"Hitelesítés szükséges a helyi virtuális gép és konténer lemezképek "
+"Hitelesítés szükséges a helyi virtuális gépek és konténerek lemezképeinek "
 "kezeléséhez."
 
 #: src/network/org.freedesktop.network1.policy:22
 msgid "Set NTP servers"
-msgstr ""
+msgstr "NTP-kiszolgálók beállítása"
 
 #: src/network/org.freedesktop.network1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to set NTP servers."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges az NTP-kiszolgálók beállításához."
 
 #: src/network/org.freedesktop.network1.policy:33
 #: src/resolve/org.freedesktop.resolve1.policy:44
 msgid "Set DNS servers"
-msgstr ""
+msgstr "DNS-kiszolgálók beállítása"
 
 #: src/network/org.freedesktop.network1.policy:34
 #: src/resolve/org.freedesktop.resolve1.policy:45
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to set DNS servers."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges a DNS-kiszolgálók beállításához."
 
 #: src/network/org.freedesktop.network1.policy:44
 #: src/resolve/org.freedesktop.resolve1.policy:55
 msgid "Set domains"
-msgstr ""
+msgstr "Domainek beállítása"
 
 #: src/network/org.freedesktop.network1.policy:45
 #: src/resolve/org.freedesktop.resolve1.policy:56
-#, fuzzy
-#| msgid "Authentication is required to stop '$(unit)'."
 msgid "Authentication is required to set domains."
-msgstr "Hitelesítés szükséges a következő leállításához: „$(unit)”."
+msgstr "Hitelesítés szükséges a domainek beállításához."
 
 #: src/network/org.freedesktop.network1.policy:55
 #: src/resolve/org.freedesktop.resolve1.policy:66
 msgid "Set default route"
-msgstr ""
+msgstr "Alapértelmezett hálózati útvonal beállítása"
 
 #: src/network/org.freedesktop.network1.policy:56
 #: src/resolve/org.freedesktop.resolve1.policy:67
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to set default route."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr ""
+"Hitelesítés szükséges az alapértelmezett hálózati útvonal beállításához."
 
 #: src/network/org.freedesktop.network1.policy:66
 #: src/resolve/org.freedesktop.resolve1.policy:77
 msgid "Enable/disable LLMNR"
-msgstr ""
+msgstr "LLMNR engedélyezése/letiltása"
 
 #: src/network/org.freedesktop.network1.policy:67
 #: src/resolve/org.freedesktop.resolve1.policy:78
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to enable or disable LLMNR."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges az LLMNR engedélyezéséhez vagy kikapcsolásához."
 
 #: src/network/org.freedesktop.network1.policy:77
 #: src/resolve/org.freedesktop.resolve1.policy:88
 msgid "Enable/disable multicast DNS"
-msgstr ""
+msgstr "Multicast DNS engedélyezése/letiltása"
 
 #: src/network/org.freedesktop.network1.policy:78
 #: src/resolve/org.freedesktop.resolve1.policy:89
-#, fuzzy
-#| msgid "Authentication is required to log into the local host."
 msgid "Authentication is required to enable or disable multicast DNS."
-msgstr "Hitelesítés szükséges a bejelentkezéshez a helyi gépre."
+msgstr ""
+"Hitelesítés szükséges a multicast DNS engedélyezéséhez vagy kikapcsolásához."
 
 #: src/network/org.freedesktop.network1.policy:88
 #: src/resolve/org.freedesktop.resolve1.policy:99
 msgid "Enable/disable DNS over TLS"
-msgstr ""
+msgstr "TLS feletti DNS engedélyezése/letiltása"
 
 #: src/network/org.freedesktop.network1.policy:89
 #: src/resolve/org.freedesktop.resolve1.policy:100
-#, fuzzy
-#| msgid "Authentication is required to set the local hostname."
 msgid "Authentication is required to enable or disable DNS over TLS."
-msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
+msgstr ""
+"Hitelesítés szükséges a TLS feletti DNS engedélyezéséhez vagy "
+"kikapcsolásához."
 
 #: src/network/org.freedesktop.network1.policy:99
 #: src/resolve/org.freedesktop.resolve1.policy:110
 msgid "Enable/disable DNSSEC"
-msgstr ""
+msgstr "DNSSEC engedélyezése/letiltása"
 
 #: src/network/org.freedesktop.network1.policy:100
 #: src/resolve/org.freedesktop.resolve1.policy:111
-#, fuzzy
-#| msgid "Authentication is required to hibernate the system."
 msgid "Authentication is required to enable or disable DNSSEC."
-msgstr "Hitelesítés szükséges a rendszer hibernálásához."
+msgstr "Hitelesítés szükséges a DNSSEC engedélyezéséhez vagy kikapcsolásához."
 
 #: src/network/org.freedesktop.network1.policy:110
 #: src/resolve/org.freedesktop.resolve1.policy:121
 msgid "Set DNSSEC Negative Trust Anchors"
-msgstr ""
+msgstr "DNSSEC Negative Trust Anchor beállítása"
 
 #: src/network/org.freedesktop.network1.policy:111
 #: src/resolve/org.freedesktop.resolve1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system locale."
 msgid "Authentication is required to set DNSSEC Negative Trust Anchors."
-msgstr "Hitelesítés szükséges a rendszer területi beállításainak megadásához."
+msgstr "Hitelestés szükséges a DNSSEC Negative Trust Anchor beállításához."
 
 #: src/network/org.freedesktop.network1.policy:121
 msgid "Revert NTP settings"
-msgstr ""
+msgstr "NTP-beállítások visszaállítása"
 
 #: src/network/org.freedesktop.network1.policy:122
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to reset NTP settings."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges az NTP-beállítások visszaállításához."
 
 #: src/network/org.freedesktop.network1.policy:132
 msgid "Revert DNS settings"
-msgstr ""
+msgstr "DNS-beállítások visszaállítása"
 
 #: src/network/org.freedesktop.network1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system time."
 msgid "Authentication is required to reset DNS settings."
-msgstr "Hitelesítés szükséges a rendszeridő beállításához."
+msgstr "Hitelesítés szükséges a DNS-beállítások visszaállításához."
 
 #: src/network/org.freedesktop.network1.policy:143
 msgid "DHCP server sends force renew message"
-msgstr ""
+msgstr "A DHCP-kiszolgáló kényszerített megújítási üzenetet küld"
 
 #: src/network/org.freedesktop.network1.policy:144
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to send force renew message."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a kényszerített megújítási üzenetet küldéséhez."
 
 #: src/network/org.freedesktop.network1.policy:154
 msgid "Renew dynamic addresses"
-msgstr ""
+msgstr "Dinamikus címke megújítása"
 
 #: src/network/org.freedesktop.network1.policy:155
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to renew dynamic addresses."
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a dinamikus címke megújításához."
 
 #: src/network/org.freedesktop.network1.policy:165
 msgid "Reload network settings"
-msgstr ""
+msgstr "Hálózati beállítások újratöltése"
 
 #: src/network/org.freedesktop.network1.policy:166
-#, fuzzy
-#| msgid "Authentication is required to reload the systemd state."
 msgid "Authentication is required to reload network settings."
-msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+msgstr "Hitelesítés szükséges a hálózati beállítások újratöltéséhez."
 
 #: src/network/org.freedesktop.network1.policy:176
 msgid "Reconfigure network interface"
-msgstr ""
+msgstr "Hálózati csatoló újrakonfigurálása"
 
 #: src/network/org.freedesktop.network1.policy:177
-#, fuzzy
-#| msgid "Authentication is required to reboot the system."
 msgid "Authentication is required to reconfigure network interface."
-msgstr "Hitelesítés szükséges a rendszer újraindításához."
+msgstr "Hitelesítés szükséges a hálózati csatoló újrakonfigurálásához."
 
 #: src/portable/org.freedesktop.portable1.policy:13
 msgid "Inspect a portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének vizsgálata"
 
 #: src/portable/org.freedesktop.portable1.policy:14
-#, fuzzy
-#| msgid "Authentication is required to import a VM or container image"
 msgid "Authentication is required to inspect a portable service image."
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép importálásához."
+msgstr ""
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének vizsgálatához."
 
 #: src/portable/org.freedesktop.portable1.policy:23
 msgid "Attach or detach a portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének csatolása vagy leválasztása"
 
 #: src/portable/org.freedesktop.portable1.policy:24
-#, fuzzy
-#| msgid "Authentication is required to attach a device to a seat."
 msgid ""
 "Authentication is required to attach or detach a portable service image."
 msgstr ""
-"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy "
-"munkaállomáshoz"
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének csatolásához "
+"vagy leválasztásához."
 
 #: src/portable/org.freedesktop.portable1.policy:34
 msgid "Delete or modify portable service image"
-msgstr ""
+msgstr "Hordozható szolgáltatás lemezképének törlése vagy módosítása"
 
 #: src/portable/org.freedesktop.portable1.policy:35
-#, fuzzy
-#| msgid "Authentication is required to download a VM or container image"
 msgid ""
 "Authentication is required to delete or modify a portable service image."
-msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép letöltéséhez."
+msgstr ""
+"Hitelesítés szükséges a hordozható szolgáltatás lemezképének törléséhez vagy "
+"módosításához."
 
 #: src/resolve/org.freedesktop.resolve1.policy:22
 msgid "Register a DNS-SD service"
-msgstr ""
+msgstr "DNS-SD szolgáltatás regisztrálása"
 
 #: src/resolve/org.freedesktop.resolve1.policy:23
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to register a DNS-SD service"
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a DNS-SD szolgáltatás regisztrálásához"
 
 #: src/resolve/org.freedesktop.resolve1.policy:33
 msgid "Unregister a DNS-SD service"
-msgstr ""
+msgstr "DNS-SD szolgáltatás kiregisztrálása"
 
 #: src/resolve/org.freedesktop.resolve1.policy:34
-#, fuzzy
-#| msgid "Authentication is required to set a wall message"
 msgid "Authentication is required to unregister a DNS-SD service"
-msgstr "Hitelesítés szükséges a falüzenet beállításához"
+msgstr "Hitelesítés szükséges a DNS-SD szolgáltatás kiregisztrálásához"
 
 #: src/resolve/org.freedesktop.resolve1.policy:132
 msgid "Revert name resolution settings"
-msgstr ""
+msgstr "Névfeloldási beállítások visszaállítása"
 
 #: src/resolve/org.freedesktop.resolve1.policy:133
-#, fuzzy
-#| msgid "Authentication is required to set the system keyboard settings."
 msgid "Authentication is required to reset name resolution settings."
-msgstr ""
-"Hitelesítés szükséges a rendszer billentyűzetbeállításainak megadásához."
+msgstr "Hitelesítés szükséges a névfeloldási beállítások visszaállításához."
 
 #: src/timedate/org.freedesktop.timedate1.policy:22
 msgid "Set system time"
@@ -1010,13 +931,12 @@ msgid "Authentication is required to restart '$(unit)'."
 msgstr "Hitelesítés szükséges a következő újraindításához: „$(unit)”."
 
 #: src/core/dbus-unit.c:535
-#, fuzzy
-#| msgid "Authentication is required to set properties on '$(unit)'."
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
 msgstr ""
-"Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”."
+"Hitelesítés szükséges a UNIX szignál elküldéséhez a következő folyamatai "
+"számára: „$(unit)”."
 
 #: src/core/dbus-unit.c:566
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
@@ -1030,24 +950,18 @@ msgstr ""
 "Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”."
 
 #: src/core/dbus-unit.c:708
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgid ""
 "Authentication is required to delete files and directories associated with "
 "'$(unit)'."
 msgstr ""
-"Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: "
-"„$(unit)”."
+"Hitelesítés szükséges a következővel kapcsolatos fájlok és könyvtárak "
+"törléséhez: „$(unit)”."
 
 #: src/core/dbus-unit.c:757
-#, fuzzy
-#| msgid ""
-#| "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgid ""
 "Authentication is required to freeze or thaw the processes of '$(unit)' unit."
 msgstr ""
-"Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: "
+"Hitelesítés szükséges a következő egység folyamatainak befagyasztásához: "
 "„$(unit)”."
 
 #~ msgid "Authentication is required to kill '$(unit)'."
index 7b9b7d2887bb6673f873c89c1f4d47245a9d6f11..09180b4b2cc7d832a3e24ab0980963edb3628899 100644 (file)
@@ -2,6 +2,22 @@
 
 ACTION=="remove", GOTO="sensor_end"
 
+# device matching the sensor's label, name and the machine's DMI data for IIO devices
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c|platform", ATTR{label}!="", \
+  IMPORT{builtin}="hwdb 'sensor:$attr{label}:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+  GOTO="sensor_end"
+
+# Before Linux v6.0, cros-ec-accel used a non-standard 'location' sysfs file
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="platform", \
+  ATTR{name}=="cros-ec-accel|cros-ec-accel-legacy", ATTR{location}=="base", \
+  IMPORT{builtin}="hwdb 'sensor:accel-base:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+  GOTO="sensor_end"
+
+SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="platform", \
+  ATTR{name}=="cros-ec-accel|cros-ec-accel-legacy", ATTR{location}=="lid", \
+  IMPORT{builtin}="hwdb 'sensor:accel-display:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
+  GOTO="sensor_end"
+
 # device matching the sensor's name and the machine's DMI data for IIO devices
 SUBSYSTEM=="iio", KERNEL=="iio*", SUBSYSTEMS=="usb|i2c|platform", \
   IMPORT{builtin}="hwdb 'sensor:modalias:$attr{modalias}:$attr{[dmi/id]modalias}'", \
index a3301be1bc8ffa0f43cb92ea38ca8128196d0302..b82ce04a39d384706a0662b50cc42b77adceb62f 100644 (file)
@@ -83,6 +83,7 @@ ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
 
 # Protocol analyzers
 ENV{ID_SIGNAL_ANALYZER}=="?*", ENV{DEVTYPE}=="usb_device", TAG+="uaccess"
+ENV{ID_SIGNAL_ANALYZER}=="?*", KERNEL=="ttyACM[0-9]*", TAG+="uaccess"
 
 # rfkill / radio killswitches
 KERNEL=="rfkill", SUBSYSTEM=="misc", TAG+="uaccess"
index c909260098066afaeb110fa9f7780c34a6a74f41..ca0a51e94901adbf7d525dbc8227b1b93fb45f7b 100644 (file)
@@ -56,6 +56,11 @@ _systemd_cgtop() {
     fi
 
     COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
+    if [ -d /sys/fs/cgroup/systemd/ ]; then
+        COMPREPLY+=( $(cd /sys/fs/cgroup/systemd/ && compgen -o nospace -o dirnames "$cur") )
+    elif [ -d /sys/fs/cgroup/ ]; then
+        COMPREPLY+=( $(cd /sys/fs/cgroup/ && compgen -o nospace -o dirnames "$cur") )
+    fi
 }
 
 complete -F _systemd_cgtop systemd-cgtop
index a4e5d77f6c8074c98136d506d440c6dd80d04d01..b6474d31a72378d85a989ee39c7bc3f47e09f89c 100644 (file)
@@ -21,6 +21,8 @@
 #include "terminal-util.h"
 #include "util.h"
 
+#define PCI_CLASS_GRAPHICS_CARD 0x30000
+
 static int help(void) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -44,6 +46,47 @@ static int help(void) {
         return 0;
 }
 
+static int has_multiple_graphics_cards(void) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        bool found = false;
+        int r;
+
+        r = sd_device_enumerator_new(&e);
+        if (r < 0)
+                return r;
+
+        r = sd_device_enumerator_add_match_subsystem(e, "pci", /* match = */ true);
+        if (r < 0)
+                return r;
+
+        /* class is an unsigned number, let's validate the value later. */
+        r = sd_device_enumerator_add_match_sysattr(e, "class", NULL, /* match = */ true);
+        if (r < 0)
+                return r;
+
+        FOREACH_DEVICE(e, dev) {
+                const char *s;
+                unsigned long c;
+
+                if (sd_device_get_sysattr_value(dev, "class", &s) < 0)
+                        continue;
+
+                if (safe_atolu(s, &c) < 0)
+                        continue;
+
+                if (c != PCI_CLASS_GRAPHICS_CARD)
+                        continue;
+
+                if (found)
+                        return true; /* This is the second device. */
+
+                found = true; /* Found the first device. */
+        }
+
+        return false;
+}
+
 static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
         const char *subsystem, *sysname, *value;
         sd_device *parent;
@@ -72,7 +115,7 @@ static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
                         return -ENODATA;
 
                 c += strspn(c, DIGITS);
-                if (*c == '-' && !STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-"))
+                if (*c == '-' && !STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-", "-eDP-"))
                         /* A connector DRM device, let's ignore all but LVDS and eDP! */
                         return -EOPNOTSUPP;
 
@@ -86,7 +129,7 @@ static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) {
                                                  value, subsystem, sysname);
 
                 /* Graphics card */
-                if (class == 0x30000) {
+                if (class == PCI_CLASS_GRAPHICS_CARD) {
                         *ret = parent;
                         return 0;
                 }
@@ -130,7 +173,7 @@ static int same_device(sd_device *a, sd_device *b) {
 
 static int validate_device(sd_device *device) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerate = NULL;
-        const char *v, *subsystem;
+        const char *v, *sysname, *subsystem;
         sd_device *parent, *other;
         int r;
 
@@ -145,80 +188,121 @@ static int validate_device(sd_device *device) {
          * device to userspace. However, we still need to make sure that we use "raw" only if no
          * "firmware" or "platform" device for the same device exists. */
 
+        r = sd_device_get_sysname(device, &sysname);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to get sysname: %m");
+
         r = sd_device_get_subsystem(device, &subsystem);
         if (r < 0)
-                return r;
+                return log_device_debug_errno(device, r, "Failed to get subsystem: %m");
         if (!streq(subsystem, "backlight"))
                 return true;
 
         r = sd_device_get_sysattr_value(device, "type", &v);
         if (r < 0)
-                return r;
+                return log_device_debug_errno(device, r, "Failed to read 'type' sysattr: %m");
         if (!streq(v, "raw"))
                 return true;
 
         r = find_pci_or_platform_parent(device, &parent);
         if (r < 0)
-                return r;
+                return log_device_debug_errno(device, r, "Failed to find PCI or platform parent: %m");
 
         r = sd_device_get_subsystem(parent, &subsystem);
         if (r < 0)
-                return r;
+                return log_device_debug_errno(parent, r, "Failed to get subsystem: %m");
+
+        if (DEBUG_LOGGING) {
+                const char *s = NULL;
+
+                (void) sd_device_get_syspath(parent, &s);
+                log_device_debug(device, "Found %s parent device: %s", subsystem, strna(s));
+        }
 
         r = sd_device_enumerator_new(&enumerate);
         if (r < 0)
-                return r;
+                return log_oom_debug();
 
         r = sd_device_enumerator_allow_uninitialized(enumerate);
         if (r < 0)
-                return r;
+                return log_debug_errno(r, "Failed to allow uninitialized devices: %m");
 
-        r = sd_device_enumerator_add_match_subsystem(enumerate, "backlight", true);
+        r = sd_device_enumerator_add_match_subsystem(enumerate, "backlight", /* match = */ true);
         if (r < 0)
-                return r;
+                return log_debug_errno(r, "Failed to add subsystem match: %m");
+
+        r = sd_device_enumerator_add_nomatch_sysname(enumerate, sysname);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to add sysname unmatch: %m");
+
+        r = sd_device_enumerator_add_match_sysattr(enumerate, "type", "platform", /* match = */ true);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to add sysattr match: %m");
+
+        r = sd_device_enumerator_add_match_sysattr(enumerate, "type", "firmware", /* match = */ true);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to add sysattr match: %m");
+
+        if (streq(subsystem, "pci")) {
+                r = has_multiple_graphics_cards();
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to check if the system has multiple graphics cards: %m");
+                if (r > 0) {
+                        /* If the system has multiple graphics cards, then we cannot associate platform
+                         * devices on non-PCI bus (especially WMI bus) with PCI devices. Let's ignore all
+                         * backlight devices that do not have the same parent PCI device. */
+                        log_debug("Found multiple graphics cards on PCI bus. "
+                                  "Skipping to associate platform backlight devices on non-PCI bus.");
+
+                        r = sd_device_enumerator_add_match_parent(enumerate, parent);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to add parent match: %m");
+                }
+        }
 
         FOREACH_DEVICE(enumerate, other) {
                 const char *other_subsystem;
                 sd_device *other_parent;
 
-                if (same_device(device, other) > 0)
-                        continue;
-
-                if (sd_device_get_sysattr_value(other, "type", &v) < 0 ||
-                    !STR_IN_SET(v, "platform", "firmware"))
-                        continue;
-
                 /* OK, so there's another backlight device, and it's a platform or firmware device.
                  * Let's see if we can verify it belongs to the same device as ours. */
-                if (find_pci_or_platform_parent(other, &other_parent) < 0)
+                r = find_pci_or_platform_parent(other, &other_parent);
+                if (r < 0) {
+                        log_device_debug_errno(other, r, "Failed to get PCI or platform parent, ignoring: %m");
                         continue;
+                }
 
                 if (same_device(parent, other_parent) > 0) {
-                        const char *device_sysname = NULL, *other_sysname = NULL;
-
                         /* Both have the same PCI parent, that means we are out. */
-
-                        (void) sd_device_get_sysname(device, &device_sysname);
-                        (void) sd_device_get_sysname(other, &other_sysname);
-
-                        log_debug("Skipping backlight device %s, since device %s is on same PCI device and takes precedence.",
-                                  device_sysname, other_sysname);
+                        if (DEBUG_LOGGING) {
+                                const char *other_sysname = NULL, *other_type = NULL;
+
+                                (void) sd_device_get_sysname(other, &other_sysname);
+                                (void) sd_device_get_sysattr_value(other, "type", &other_type);
+                                log_device_debug(device,
+                                                 "Found another %s backlight device %s on the same PCI, skipping.",
+                                                 strna(other_type), strna(other_sysname));
+                        }
                         return false;
                 }
 
-                if (sd_device_get_subsystem(other_parent, &other_subsystem) < 0)
+                r = sd_device_get_subsystem(other_parent, &other_subsystem);
+                if (r < 0) {
+                        log_device_debug_errno(other_parent, r, "Failed to get subsystem, ignoring: %m");
                         continue;
+                }
 
                 if (streq(other_subsystem, "platform") && streq(subsystem, "pci")) {
-                        const char *device_sysname = NULL, *other_sysname = NULL;
-
                         /* The other is connected to the platform bus and we are a PCI device, that also means we are out. */
-
-                        (void) sd_device_get_sysname(device, &device_sysname);
-                        (void) sd_device_get_sysname(other, &other_sysname);
-
-                        log_debug("Skipping backlight device %s, since device %s is a platform device and takes precedence.",
-                                  device_sysname, other_sysname);
+                        if (DEBUG_LOGGING) {
+                                const char *other_sysname = NULL, *other_type = NULL;
+
+                                (void) sd_device_get_sysname(other, &other_sysname);
+                                (void) sd_device_get_sysattr_value(other, "type", &other_type);
+                                log_device_debug(device,
+                                                 "Found another %s backlight device %s, which has higher precedence, skipping.",
+                                                 strna(other_type), strna(other_sysname));
+                        }
                         return false;
                 }
         }
index 4c413a8d174cc50ed96bb5a04c9c9ff8ec8793d3..df6d5b7bbb423ee9612dc19ab5df0666ea6e1d66 100644 (file)
@@ -86,6 +86,7 @@ bool cpu_accounting_is_cheap(void);
 
 /* Special values for all weight knobs on unified hierarchy */
 #define CGROUP_WEIGHT_INVALID UINT64_MAX
+#define CGROUP_WEIGHT_IDLE UINT64_C(0)
 #define CGROUP_WEIGHT_MIN UINT64_C(1)
 #define CGROUP_WEIGHT_MAX UINT64_C(10000)
 #define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
index 0a1ae023a37cf263556e3a879cf760b5e8ae783c..2b4de29021a7eab930b17098a918e2156cd0d085 100644 (file)
@@ -5,6 +5,11 @@
 #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
 #define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC)
 
+/* We use an extra-long timeout for the reload. This is because a reload or reexec means generators are rerun
+ * which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can
+ * have their timeout, and for everything else there's the same time budget in place. */
+#define DAEMON_RELOAD_TIMEOUT_SEC (DEFAULT_TIMEOUT_USEC * 2)
+
 #define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC)
 #define DEFAULT_START_LIMIT_BURST 5
 
index c609ea6ce017a52e662df5169c87dc42315cc76c..0a6a54f8f139dded22de9ac299e9d81320a24e3d 100644 (file)
@@ -33,6 +33,15 @@ char *hw_addr_to_string_full(
         return buffer;
 }
 
+struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) {
+        assert(addr);
+        assert(length <= HW_ADDR_MAX_SIZE);
+
+        addr->length = length;
+        memcpy_safe(addr->bytes, bytes, length);
+        return addr;
+}
+
 int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) {
         int r;
 
index 32f45fe8135ea6236c4b678d19ca8cb4f2161801..83ed77d634513d189c30ac84542013833298fd6d 100644 (file)
@@ -52,6 +52,8 @@ static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buff
 
 #define HW_ADDR_NULL ((const struct hw_addr_data){})
 
+struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length);
+
 void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state);
 int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b);
 static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) {
index cc25222c32df14403ea2657ea71bc52cde6d0e23..d1272fb04b1c12a9824aaad077de2f9c203c3a51 100644 (file)
@@ -398,10 +398,6 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
         return ret;
 }
 
-int touch(const char *path) {
-        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
-}
-
 int symlink_idempotent(const char *from, const char *to, bool make_relative) {
         _cleanup_free_ char *relpath = NULL;
         int r;
index e48cf6800fac1796ba7d403a592adb2c1fe4d603..080959d3b99b9e221803276ba49bf0cea9518bcb 100644 (file)
@@ -13,6 +13,7 @@
 #include "alloc-util.h"
 #include "errno-util.h"
 #include "time-util.h"
+#include "user-util.h"
 
 #define MODE_INVALID ((mode_t) -1)
 
@@ -50,7 +51,10 @@ int stat_warn_permissions(const char *path, const struct stat *st);
         RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
 
 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
-int touch(const char *path);
+
+static inline int touch(const char *path) {
+        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
+}
 
 int symlink_idempotent(const char *from, const char *to, bool make_relative);
 
index 6addb76f1b2d52cd18df19794bcbef922db99b77..5fac467185710bc8f73038d4c33bb84cfd08293f 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "hash-funcs.h"
 #include "path-util.h"
+#include "strv.h"
 
 void string_hash_func(const char *p, struct siphash *state) {
         siphash24_compress(p, strlen(p) + 1, state);
@@ -15,6 +16,9 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
 DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
                      char, string_hash_func, string_compare_func, free,
                      void, free);
+DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free,
+                     char, string_hash_func, string_compare_func, free,
+                     char*, strv_free);
 
 void path_hash_func(const char *q, struct siphash *state) {
         bool add_slash = false;
index c537c6af7e8cc2a9f8761cf15e53aeb72524ee15..c14302ec72285c5fab5feb6b7b3edac368a13571 100644 (file)
@@ -78,6 +78,7 @@ void string_hash_func(const char *p, struct siphash *state);
 extern const struct hash_ops string_hash_ops;
 extern const struct hash_ops string_hash_ops_free;
 extern const struct hash_ops string_hash_ops_free_free;
+extern const struct hash_ops string_hash_ops_free_strv_free;
 
 void path_hash_func(const char *p, struct siphash *state);
 extern const struct hash_ops path_hash_ops;
index e40ab3f5b6f3f836e2f1ab01015b72db9f6f3565..88657d5775059f1781d76b5b1063039e046452a5 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <errno.h>
+#include <fnmatch.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -17,6 +18,7 @@
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fs-util.h"
+#include "glob-util.h"
 #include "log.h"
 #include "macro.h"
 #include "path-util.h"
@@ -1310,3 +1312,63 @@ bool prefixed_path_strv_contains(char **l, const char *path) {
 
         return false;
 }
+
+int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
+        assert(pattern);
+        assert(prefix);
+
+        for (const char *a = pattern, *b = prefix;;) {
+                _cleanup_free_ char *g = NULL, *h = NULL;
+                const char *p, *q;
+                int r, s;
+
+                r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p);
+                if (r < 0)
+                        return r;
+
+                s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q);
+                if (s < 0)
+                        return s;
+
+                if (s == 0) {
+                        /* The pattern matches the prefix. */
+                        if (ret) {
+                                char *t;
+
+                                t = path_join(prefix, p);
+                                if (!t)
+                                        return -ENOMEM;
+
+                                *ret = t;
+                        }
+                        return true;
+                }
+
+                if (r == 0)
+                        break;
+
+                if (r == s && strneq(p, q, r))
+                        continue; /* common component. Check next. */
+
+                g = strndup(p, r);
+                if (!g)
+                        return -ENOMEM;
+
+                if (!string_is_glob(g))
+                        break;
+
+                /* We found a glob component. Check if the glob pattern matches the prefix component. */
+
+                h = strndup(q, s);
+                if (!h)
+                        return -ENOMEM;
+
+                if (fnmatch(g, h, 0) != 0)
+                        break;
+        }
+
+        /* The pattern does not match the prefix. */
+        if (ret)
+                *ret = NULL;
+        return false;
+}
index bb200872216068875c7d1fc98b80a1cbe2a17dc8..757ed722d51c0f34814ad81ac3fcbaa6e55f4f01 100644 (file)
@@ -196,3 +196,5 @@ static inline const char *empty_to_root(const char *path) {
 
 bool path_strv_contains(char **l, const char *path);
 bool prefixed_path_strv_contains(char **l, const char *path);
+
+int path_glob_can_match(const char *pattern, const char *prefix, char **ret);
index 9423a0805dd132b708fbb8e5671550e5c2320e76..d8734cc7d0faf78edcfc3f21044228df73c45b0e 100644 (file)
@@ -1,9 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#if defined(__i386__) || defined(__x86_64__)
-#include <cpuid.h>
-#endif
-
 #include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
 #include "sha256.h"
 #include "time-util.h"
 
-/* This is a "best effort" kind of thing, but has no real security value.
- * So, this should only be used by random_bytes(), which is not meant for
- * crypto. This could be made better, but we're *not* trying to roll a
- * userspace prng here, or even have forward secrecy, but rather just do
- * the shortest thing that is at least better than libc rand(). */
+/* This is a "best effort" kind of thing, but has no real security value.  So, this should only be used by
+ * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
+ * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least
+ * better than libc rand(). */
 static void fallback_random_bytes(void *p, size_t n) {
         static thread_local uint64_t fallback_counter = 0;
         struct {
@@ -53,7 +48,7 @@ static void fallback_random_bytes(void *p, size_t n) {
                 .stamp_mono = now(CLOCK_MONOTONIC),
                 .stamp_real = now(CLOCK_REALTIME),
                 .pid = getpid(),
-                .tid = gettid()
+                .tid = gettid(),
         };
 
 #if HAVE_SYS_AUXV_H
index f04463157a514f34c7c273732d736f02d1fb6399..ddeeed0c3d0f989dbf211ccca46b2fb0eb0bfffc 100644 (file)
 #include "verbs.h"
 #include "virt.h"
 
+/* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
+ * stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
+ * string, but we limit the length to something reasonable to prevent from the firmware
+ * having to deal with a potentially too long string. */
+#define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
+
 static char *arg_esp_path = NULL;
 static char *arg_xbootldr_path = NULL;
 static bool arg_print_esp_path = false;
@@ -85,6 +91,7 @@ static enum {
         ARG_INSTALL_SOURCE_HOST,
         ARG_INSTALL_SOURCE_AUTO,
 } arg_install_source = ARG_INSTALL_SOURCE_AUTO;
+static char *arg_efi_boot_option_description = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -92,12 +99,17 @@ STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
 
 static const char *arg_dollar_boot_path(void) {
         /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
         return arg_xbootldr_path ?: arg_esp_path;
 }
 
+static const char *pick_efi_boot_option_description(void) {
+        return arg_efi_boot_option_description ?: "Linux Boot Manager";
+}
+
 static int acquire_esp(
                 bool unprivileged_mode,
                 bool graceful,
@@ -321,7 +333,7 @@ static int settle_entry_token(void) {
                 break;
         }
 
-        if (isempty(arg_entry_token) || !string_is_safe(arg_entry_token))
+        if (isempty(arg_entry_token) || !(utf8_is_valid(arg_entry_token) && string_is_safe(arg_entry_token)))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
 
         log_debug("Using entry token: %s", arg_entry_token);
@@ -1139,13 +1151,13 @@ static int install_variables(const char *esp_path,
                                        "Failed to determine current boot order: %m");
 
         if (first || r == 0) {
-                r = efi_add_boot_option(slot, "Linux Boot Manager",
+                r = efi_add_boot_option(slot, pick_efi_boot_option_description(),
                                         part, pstart, psize,
                                         uuid, path);
                 if (r < 0)
                         return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
 
-                log_info("Created EFI boot entry \"Linux Boot Manager\".");
+                log_info("Created EFI boot entry \"%s\".", pick_efi_boot_option_description());
         }
 
         return insert_into_order(slot, first);
@@ -1465,6 +1477,8 @@ static int help(int argc, char *argv[], void *userdata) {
                "                       Generate JSON output\n"
                "     --all-architectures\n"
                "                       Install all supported EFI architectures\n"
+               "     --efi-boot-option-description=DESCRIPTION\n"
+               "                       Description of the entry in the boot option list\n"
                "\nSee the %2$s for details.\n",
                program_invocation_short_name,
                link,
@@ -1491,29 +1505,31 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ENTRY_TOKEN,
                 ARG_JSON,
                 ARG_ARCH_ALL,
+                ARG_EFI_BOOT_OPTION_DESCRIPTION,
         };
 
         static const struct option options[] = {
-                { "help",                      no_argument,       NULL, 'h'                           },
-                { "version",                   no_argument,       NULL, ARG_VERSION                   },
-                { "esp-path",                  required_argument, NULL, ARG_ESP_PATH                  },
-                { "path",                      required_argument, NULL, ARG_ESP_PATH                  }, /* Compatibility alias */
-                { "boot-path",                 required_argument, NULL, ARG_BOOT_PATH                 },
-                { "root",                      required_argument, NULL, ARG_ROOT                      },
-                { "image",                     required_argument, NULL, ARG_IMAGE                     },
-                { "install-source",            required_argument, NULL, ARG_INSTALL_SOURCE            },
-                { "print-esp-path",            no_argument,       NULL, 'p'                           },
-                { "print-path",                no_argument,       NULL, 'p'                           }, /* Compatibility alias */
-                { "print-boot-path",           no_argument,       NULL, 'x'                           },
-                { "no-variables",              no_argument,       NULL, ARG_NO_VARIABLES              },
-                { "no-pager",                  no_argument,       NULL, ARG_NO_PAGER                  },
-                { "graceful",                  no_argument,       NULL, ARG_GRACEFUL                  },
-                { "quiet",                     no_argument,       NULL, 'q'                           },
-                { "make-entry-directory",      required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY      },
-                { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY      }, /* Compatibility alias */
-                { "entry-token",               required_argument, NULL, ARG_ENTRY_TOKEN               },
-                { "json",                      required_argument, NULL, ARG_JSON                      },
-                { "all-architectures",         no_argument,       NULL, ARG_ARCH_ALL                  },
+                { "help",                        no_argument,       NULL, 'h'                             },
+                { "version",                     no_argument,       NULL, ARG_VERSION                     },
+                { "esp-path",                    required_argument, NULL, ARG_ESP_PATH                    },
+                { "path",                        required_argument, NULL, ARG_ESP_PATH                    }, /* Compatibility alias */
+                { "boot-path",                   required_argument, NULL, ARG_BOOT_PATH                   },
+                { "root",                        required_argument, NULL, ARG_ROOT                        },
+                { "image",                       required_argument, NULL, ARG_IMAGE                       },
+                { "install-source",              required_argument, NULL, ARG_INSTALL_SOURCE              },
+                { "print-esp-path",              no_argument,       NULL, 'p'                             },
+                { "print-path",                  no_argument,       NULL, 'p'                             }, /* Compatibility alias */
+                { "print-boot-path",             no_argument,       NULL, 'x'                             },
+                { "no-variables",                no_argument,       NULL, ARG_NO_VARIABLES                },
+                { "no-pager",                    no_argument,       NULL, ARG_NO_PAGER                    },
+                { "graceful",                    no_argument,       NULL, ARG_GRACEFUL                    },
+                { "quiet",                       no_argument,       NULL, 'q'                             },
+                { "make-entry-directory",        required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY        },
+                { "make-machine-id-directory",   required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY        }, /* Compatibility alias */
+                { "entry-token",                 required_argument, NULL, ARG_ENTRY_TOKEN                 },
+                { "json",                        required_argument, NULL, ARG_JSON                        },
+                { "all-architectures",           no_argument,       NULL, ARG_ARCH_ALL                    },
+                { "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
                 {}
         };
 
@@ -1647,6 +1663,22 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_arch_all = true;
                         break;
 
+                case ARG_EFI_BOOT_OPTION_DESCRIPTION:
+                        if (isempty(optarg) || !(string_is_safe(optarg) && utf8_is_valid(optarg))) {
+                                _cleanup_free_ char *escaped = NULL;
+
+                                escaped = cescape(optarg);
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid --efi-boot-option-description=: %s", strna(escaped));
+                        }
+                        if (strlen(optarg) > EFI_BOOT_OPTION_DESCRIPTION_MAX)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "--efi-boot-option-description= too long: %zu > %zu", strlen(optarg), EFI_BOOT_OPTION_DESCRIPTION_MAX);
+                        r = free_and_strdup_warn(&arg_efi_boot_option_description, optarg);
+                        if (r < 0)
+                                return r;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -1838,8 +1870,11 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                 bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
 
                 print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
-                if (have_bootloader_esp_uuid && !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
-                        printf("WARNING: The boot loader reports a different ESP UUID than detected!\n");
+                if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
+                    !sd_id128_equal(esp_uuid, bootloader_esp_uuid))
+                        printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
+                               SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
+                               SD_ID128_FORMAT_VAL(esp_uuid));
 
                 if (stub) {
                         printf("         Stub: %s\n", stub);
index 87771c477dd6c669667247f28ad99a39bdbad8be..9c1d95e67256d43f1dcfb8e536dd54e32863e993 100644 (file)
@@ -2495,7 +2495,7 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
                 config_add_entry(config, entry);
 
                 if (config->secure_boot_enroll == ENROLL_FORCE && strcaseeq16(dirent->FileName, u"auto"))
-                        /* if we auto enroll sucessfully this call does not return, if it fails we still
+                        /* if we auto enroll successfully this call does not return, if it fails we still
                          * want to add other potential entries to the menu */
                         secure_boot_enroll_at(root_dir, entry->path);
         }
index 0e04a6ee0666ae351de71ae8abe6df212df9210e..3cbffdbbeb59489e9fbea477415527e8b6b90f76 100644 (file)
@@ -141,7 +141,7 @@ EFI_STATUS linux_exec(
         */
         /* allocate SizeOfImage + SectionAlignment because the new_buffer can move up to Alignment-1 bytes */
         kernel.num = EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment);
-        err = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel.num, &kernel.addr);
+        err = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode, kernel.num, &kernel.addr);
         if (err != EFI_SUCCESS)
                 return EFI_OUT_OF_RESOURCES;
         new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment));
index 127b4e17a3a722c6ef90a95d8c732a8053f30e5d..95785dfd5d83d41895079a7f38b24b1a7877533f 100644 (file)
@@ -266,11 +266,19 @@ efi_ldflags = [
         efi_crt0,
 ]
 
-possible_link_flags = [
-        '-Wl,--no-warn-execstack',
-        '-Wl,--no-warn-rwx-segments',
-]
-efi_ldflags += cc.get_supported_link_arguments(possible_link_flags)
+foreach arg : ['-Wl,--no-warn-execstack',
+               '-Wl,--no-warn-rwx-segments']
+        # We need to check the correct linker for supported args. This is what
+        # cc.has_multi_link_arguments() is for, but it helpfully overrides our
+        # choice of linker by putting its own -fuse-ld= arg after ours.
+        if run_command('bash', '-c',
+                       'exec "$@" -x c -o/dev/null <(echo "int main(void){return 0;}")' +
+                       ' -fuse-ld=' + efi_ld + ' -Wl,--fatal-warnings ' + arg,
+                       'bash', cc.cmd_array(),
+                       check : false).returncode() == 0
+                efi_ldflags += arg
+        endif
+endforeach
 
 if efi_arch[1] in ['aarch64', 'arm', 'riscv64']
         efi_ldflags += ['-shared']
index 49ece4196196a94160d1bf4d72fbf5ee34231e52..003ae8c99a0bc192bac180a50282093e4f98d7b0 100644 (file)
@@ -239,7 +239,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         }
 
         /* if we are not in secure boot mode, or none was provided, accept a custom command line and replace
-         * the built-in one. We also do a superficial check whether first chararacter of passed command line
+         * the built-in one. We also do a superficial check whether first character of passed command line
          * is printable character (for compat with some Dell systems which fill in garbage?). */
         if ((!secure_boot_enabled() || cmdline_len == 0) &&
             loaded_image->LoadOptionsSize > 0 &&
index 871d79e0d2532dcccbf1976fbefa94e1d9d388f1..8ecbd69031b80eed3877830162f79973382bdae0 100644 (file)
@@ -13,6 +13,7 @@
 #include "bpf-socket-bind.h"
 #include "btrfs-util.h"
 #include "bus-error.h"
+#include "bus-locator.h"
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
@@ -948,10 +949,25 @@ static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t qu
 static void cgroup_apply_unified_cpu_weight(Unit *u, uint64_t weight) {
         char buf[DECIMAL_STR_MAX(uint64_t) + 2];
 
+        if (weight == CGROUP_WEIGHT_IDLE)
+                return;
         xsprintf(buf, "%" PRIu64 "\n", weight);
         (void) set_attribute_and_warn(u, "cpu", "cpu.weight", buf);
 }
 
+static void cgroup_apply_unified_cpu_idle(Unit *u, uint64_t weight) {
+        int r;
+        bool is_idle;
+        const char *idle_val;
+
+        is_idle = weight == CGROUP_WEIGHT_IDLE;
+        idle_val = one_zero(is_idle);
+        r = cg_set_attribute("cpu", u->cgroup_path, "cpu.idle", idle_val);
+        if (r < 0 && (r != -ENOENT || is_idle))
+                log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%s': %m",
+                                    "cpu.idle", empty_to_root(u->cgroup_path), idle_val);
+}
+
 static void cgroup_apply_unified_cpu_quota(Unit *u, usec_t quota, usec_t period) {
         char buf[(DECIMAL_STR_MAX(usec_t) + 1) * 2 + 1];
 
@@ -992,6 +1008,10 @@ static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) {
 }
 
 static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) {
+        /* we don't support idle in cgroupv1 */
+        if (weight == CGROUP_WEIGHT_IDLE)
+                return CGROUP_CPU_SHARES_MIN;
+
         return CLAMP(weight * CGROUP_CPU_SHARES_DEFAULT / CGROUP_WEIGHT_DEFAULT,
                      CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX);
 }
@@ -1397,6 +1417,7 @@ static void cgroup_context_apply(
                         } else
                                 weight = CGROUP_WEIGHT_DEFAULT;
 
+                        cgroup_apply_unified_cpu_idle(u, weight);
                         cgroup_apply_unified_cpu_weight(u, weight);
                         cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
 
@@ -2261,14 +2282,12 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
         pp = strjoina("/", pp, suffix_path);
         path_simplify(pp);
 
-        r = sd_bus_call_method(u->manager->system_bus,
-                               "org.freedesktop.systemd1",
-                               "/org/freedesktop/systemd1",
-                               "org.freedesktop.systemd1.Manager",
-                               "AttachProcessesToUnit",
-                               &error, NULL,
-                               "ssau",
-                               NULL /* empty unit name means client's unit, i.e. us */, pp, 1, (uint32_t) pid);
+        r = bus_call_method(u->manager->system_bus,
+                            bus_systemd_mgr,
+                            "AttachProcessesToUnit",
+                            &error, NULL,
+                            "ssau",
+                            NULL /* empty unit name means client's unit, i.e. us */, pp, 1, (uint32_t) pid);
         if (r < 0)
                 return log_unit_debug_errno(u, r, "Failed to attach unit process " PID_FMT " via the bus: %s", pid, bus_error_message(&error, r));
 
index 4fc4fb0021612b1604e1059902a25a8d747bc6a2..015dc238d682f16b33af5b060b6184484cb24565 100644 (file)
@@ -894,7 +894,6 @@ static int bus_cgroup_set_boolean(
         }
 
 DISABLE_WARNING_TYPE_LIMITS;
-BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
 BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
 BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
 BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
@@ -903,6 +902,35 @@ BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memo
 BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
 REENABLE_WARNING;
 
+static int bus_cgroup_set_cpu_weight(
+                Unit *u,
+                const char *name,
+                uint64_t *p,
+                sd_bus_message *message,
+                UnitWriteFlags flags,
+                sd_bus_error *error) {
+        uint64_t v;
+        int r;
+        assert(p);
+        r = sd_bus_message_read(message, "t", &v);
+        if (r < 0)
+                return r;
+        if (!CGROUP_WEIGHT_IS_OK(v) && v != CGROUP_WEIGHT_IDLE)
+                return sd_bus_error_setf(
+                                error, SD_BUS_ERROR_INVALID_ARGS, "Value specified in %s is out of range", name);
+        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                *p = v;
+                unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+                if (v == CGROUP_WEIGHT_INVALID)
+                        unit_write_settingf(u, flags, name, "%s=", name);
+                else if (v == CGROUP_WEIGHT_IDLE)
+                        unit_write_settingf(u, flags, name, "%s=idle", name);
+                else
+                        unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
+        }
+        return 1;
+}
+
 static int bus_cgroup_set_tasks_max(
                 Unit *u,
                 const char *name,
index 52521c414642062f4a45db752aa79c97854a5af2..95defd36a3781db264ab29bec56d89895c152272 100644 (file)
@@ -2791,6 +2791,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultTimeoutAbortUSec", "t", property_get_default_timeout_abort_usec, 0, 0),
+        SD_BUS_PROPERTY("DefaultDeviceTimeoutUSec", "t", bus_property_get_usec, offsetof(Manager, default_device_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
         /* The following two items are obsolete alias */
index 4650df4d1c1339c18e8554e8a7029736e85225a9..ee013e1bc5af37d43d9e68473da4bebf00bd7dde 100644 (file)
@@ -2437,10 +2437,6 @@ int bus_unit_set_properties(
                 if (r < 0)
                         return r;
 
-                if (!UNIT_VTABLE(u)->bus_set_property)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY,
-                                                 "Objects of this type do not support setting properties.");
-
                 r = sd_bus_message_enter_container(message, 'v', NULL);
                 if (r < 0)
                         return r;
@@ -2448,7 +2444,10 @@ int bus_unit_set_properties(
                 /* If not for real, then mask out the two target flags */
                 f = for_real ? flags : (flags & ~(UNIT_RUNTIME|UNIT_PERSISTENT));
 
-                r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
+                if (UNIT_VTABLE(u)->bus_set_property)
+                        r = UNIT_VTABLE(u)->bus_set_property(u, name, message, f, error);
+                else
+                        r = 0;
                 if (r == 0 && u->transient && u->load_state == UNIT_STUB)
                         r = bus_unit_set_transient_property(u, name, message, f, error);
                 if (r == 0)
index 4f9bf24db88ffdaca8d4d0d99893ac0c2e20e92b..d6710262a99360f2ec31ebbaefdffe6eb1e4268b 100644 (file)
@@ -101,7 +101,7 @@ static void device_init(Unit *u) {
          * indefinitely for plugged in devices, something which cannot
          * happen for the other units since their operations time out
          * anyway. */
-        u->job_running_timeout = u->manager->default_timeout_start_usec;
+        u->job_running_timeout = u->manager->default_device_timeout_usec;
 
         u->ignore_on_isolate = true;
 
@@ -547,18 +547,24 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) {
         if (d->state != DEVICE_DEAD)
                 /* So here's a special hack, to compensate for the fact that the udev database's reload cycles are not
                  * synchronized with our own reload cycles: when we detect that the SYSTEMD_WANTS property of a device
-                 * changes while the device unit is already up, let's manually trigger any new units listed in it not
-                 * seen before. This typically happens during the boot-time switch root transition, as udev devices
-                 * will generally already be up in the initrd, but SYSTEMD_WANTS properties get then added through udev
-                 * rules only available on the host system, and thus only when the initial udev coldplug trigger runs.
+                 * changes while the device unit is already up, let's skip to trigger units that were already listed
+                 * and are active, and start units otherwise. This typically happens during the boot-time switch root
+                 * transition, as udev devices will generally already be up in the initrd, but SYSTEMD_WANTS properties
+                 * get then added through udev rules only available on the host system, and thus only when the initial
+                 * udev coldplug trigger runs.
                  *
                  * We do this only if the device has been up already when we parse this, as otherwise the usual
                  * dependency logic that is run from the dead → plugged transition will trigger these deps. */
                 STRV_FOREACH(i, added) {
                         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                        if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
-                                continue;
+                        if (strv_contains(d->wants_property, *i)) {
+                                Unit *v;
+
+                                v = manager_get_unit(u->manager, *i);
+                                if (v && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(v)))
+                                        continue; /* The unit was already listed and is running. */
+                        }
 
                         r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
                         if (r < 0)
index f4488dd6924151e2ae8bfc420b6a0f36b89a2f71..966631d44eca23207cb89d98a24c50dcc880c085 100644 (file)
@@ -117,6 +117,9 @@ int kmod_setup(void) {
 
                 /* qemu_fw_cfg would be loaded by udev later, but we want to import credentials from it super early */
                 { "qemu_fw_cfg", "/sys/firmware/qemu_fw_cfg", false, false,  in_qemu   },
+
+                /* dmi-sysfs is needed to import credentials from it super early */
+                { "dmi-sysfs", "/sys/firmware/dmi/entries", false, false,  NULL   },
         };
         _cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
         unsigned i;
index 54c1c0bb56bfe81d4770da5ac3c99c551dd92944..7675b7bb2e74619f59f0db8b52beadc1a436d097 100644 (file)
 {{type}}.AllowedMemoryNodes,               config_parse_allowed_cpuset,                 0,                                  offsetof({{type}}, cgroup_context.cpuset_mems)
 {{type}}.StartupAllowedMemoryNodes,        config_parse_allowed_cpuset,                 0,                                  offsetof({{type}}, cgroup_context.startup_cpuset_mems)
 {{type}}.CPUAccounting,                    config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.cpu_accounting)
-{{type}}.CPUWeight,                        config_parse_cg_weight,                      0,                                  offsetof({{type}}, cgroup_context.cpu_weight)
-{{type}}.StartupCPUWeight,                 config_parse_cg_weight,                      0,                                  offsetof({{type}}, cgroup_context.startup_cpu_weight)
+{{type}}.CPUWeight,                        config_parse_cg_cpu_weight,                  0,                                  offsetof({{type}}, cgroup_context.cpu_weight)
+{{type}}.StartupCPUWeight,                 config_parse_cg_cpu_weight,                  0,                                  offsetof({{type}}, cgroup_context.startup_cpu_weight)
 {{type}}.CPUShares,                        config_parse_cpu_shares,                     0,                                  offsetof({{type}}, cgroup_context.cpu_shares)
 {{type}}.StartupCPUShares,                 config_parse_cpu_shares,                     0,                                  offsetof({{type}}, cgroup_context.startup_cpu_shares)
 {{type}}.CPUQuota,                         config_parse_cpu_quota,                      0,                                  offsetof({{type}}, cgroup_context)
index d16c7b1df2b6919b9c71b5774700d4592c8ba975..0a2d4d4035b21b7edc86252fd7bb8f3b5182a06d 100644 (file)
@@ -147,6 +147,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_prefer
 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
 DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
 DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
+DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
 DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
 DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
@@ -6286,6 +6287,7 @@ void unit_dump_config_items(FILE *f) {
                 { config_parse_restrict_filesystems,  "FILESYSTEMS"  },
                 { config_parse_cpu_shares,            "SHARES" },
                 { config_parse_cg_weight,             "WEIGHT" },
+                { config_parse_cg_cpu_weight,         "CPUWEIGHT" },
                 { config_parse_memory_limit,          "LIMIT" },
                 { config_parse_device_allow,          "DEVICE" },
                 { config_parse_device_policy,         "POLICY" },
index 26b8de28f7a09d6a18c4e2f43daa817393978832..8842d7ddc8acdad3576d0085d256b26aa06d8d12 100644 (file)
@@ -78,6 +78,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
 CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
 CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
 CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
+CONFIG_PARSER_PROTOTYPE(config_parse_cg_cpu_weight);
 CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
 CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
 CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
index 9ad3983b209b6e750ea749e9f876dafef8aafe0b..9ad208fdfca83e2e7cd1158b5a84e03ce4f87df6 100644 (file)
@@ -134,6 +134,7 @@ static usec_t arg_default_restart_usec;
 static usec_t arg_default_timeout_start_usec;
 static usec_t arg_default_timeout_stop_usec;
 static usec_t arg_default_timeout_abort_usec;
+static usec_t arg_default_device_timeout_usec;
 static bool arg_default_timeout_abort_set;
 static usec_t arg_default_start_limit_interval;
 static unsigned arg_default_start_limit_burst;
@@ -627,6 +628,7 @@ static int parse_config_file(void) {
                 { "Manager", "DefaultTimeoutStartSec",       config_parse_sec,                   0,                        &arg_default_timeout_start_usec   },
                 { "Manager", "DefaultTimeoutStopSec",        config_parse_sec,                   0,                        &arg_default_timeout_stop_usec    },
                 { "Manager", "DefaultTimeoutAbortSec",       config_parse_default_timeout_abort, 0,                        NULL                              },
+                { "Manager", "DefaultDeviceTimeoutSec",      config_parse_sec,                   0,                        &arg_default_device_timeout_usec  },
                 { "Manager", "DefaultRestartSec",            config_parse_sec,                   0,                        &arg_default_restart_usec         },
                 { "Manager", "DefaultStartLimitInterval",    config_parse_sec,                   0,                        &arg_default_start_limit_interval }, /* obsolete alias */
                 { "Manager", "DefaultStartLimitIntervalSec", config_parse_sec,                   0,                        &arg_default_start_limit_interval },
@@ -689,6 +691,7 @@ static int parse_config_file(void) {
                         config_item_table_lookup, items,
                         CONFIG_PARSE_WARN,
                         NULL,
+                        NULL,
                         NULL);
 
         /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use
@@ -716,6 +719,7 @@ static void set_manager_defaults(Manager *m) {
         m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
         m->default_timeout_abort_usec = arg_default_timeout_abort_usec;
         m->default_timeout_abort_set = arg_default_timeout_abort_set;
+        m->default_device_timeout_usec = arg_default_device_timeout_usec;
         m->default_restart_usec = arg_default_restart_usec;
         m->default_start_limit_interval = arg_default_start_limit_interval;
         m->default_start_limit_burst = arg_default_start_limit_burst;
@@ -2389,6 +2393,7 @@ static void reset_arguments(void) {
         arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
         arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
         arg_default_timeout_abort_set = false;
+        arg_default_device_timeout_usec = DEFAULT_TIMEOUT_USEC;
         arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
         arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
         arg_runtime_watchdog = 0;
index f1536415103c78995b8e0a95810b334a365989e4..d21698a99bfbafd7de10ecd3b8d70d37c3f41c18 100644 (file)
@@ -835,6 +835,7 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager *
                 .default_timeout_start_usec = DEFAULT_TIMEOUT_USEC,
                 .default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC,
                 .default_restart_usec = DEFAULT_RESTART_USEC,
+                .default_device_timeout_usec = DEFAULT_TIMEOUT_USEC,
 
                 .original_log_level = -1,
                 .original_log_target = _LOG_TARGET_INVALID,
index e4603daff29eb6d3c087279477bb9b1889fb3ea1..ab4b30cfe7edc3f930f6110e91ae56a6ba6494dd 100644 (file)
@@ -356,6 +356,7 @@ struct Manager {
         ExecOutput default_std_output, default_std_error;
 
         usec_t default_restart_usec, default_timeout_start_usec, default_timeout_stop_usec;
+        usec_t default_device_timeout_usec;
         usec_t default_timeout_abort_usec;
         bool default_timeout_abort_set;
 
index 016afe4d9e90be208935354aa63f0f6b3008967d..d774467658b3ae394ca6578ee2c7b679d1bf31e0 100644 (file)
@@ -926,7 +926,7 @@ static int mount_private_dev(MountEntry *m) {
 
         dev = strjoina(temporary_mount, "/dev");
         (void) mkdir(dev, 0755);
-        r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_DEV);
+        r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_PRIVATE_DEV);
         if (r < 0)
                 goto fail;
 
index 4b1c5d303d17f894199c97ee836a13bdc24b9850..54a6cc63e4b4a9d55c4fde55ed20264311a1ab3f 100644 (file)
@@ -490,7 +490,7 @@ static int scope_start(Unit *u) {
         (void) unit_reset_accounting(u);
 
         /* We check only for User= option to keep behavior consistent with logic for service units,
-         * i.e. having 'Delegate=true Group=foo' w/o specifing User= has no effect. */
+         * i.e. having 'Delegate=true Group=foo' w/o specifying User= has no effect. */
         if (s->user && unit_cgroup_delegate(u))
                 return scope_enter_start_chown(s);
 
@@ -627,6 +627,33 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
                 unit_prune_cgroup(u);
 }
 
+static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
+        Scope *s = SCOPE(u);
+
+        if (managed_oom)
+                log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
+        else
+                log_unit_debug(u, "Process of control group was killed by the OOM killer.");
+
+        /* This will probably need to be modified when scope units get an oom-policy */
+        switch (s->state) {
+
+        case SCOPE_START_CHOWN:
+        case SCOPE_RUNNING:
+        case SCOPE_STOP_SIGTERM:
+                scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_OOM_KILL);
+                break;
+
+        case SCOPE_STOP_SIGKILL:
+                if (s->result == SCOPE_SUCCESS)
+                        s->result = SCOPE_FAILURE_OOM_KILL;
+                break;
+        /* SCOPE_DEAD, SCOPE_ABANDONED, and SCOPE_FAILED end up in default */
+        default:
+                ;
+        }
+}
+
 static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         Scope *s = SCOPE(u);
 
@@ -755,6 +782,7 @@ static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
         [SCOPE_SUCCESS]           = "success",
         [SCOPE_FAILURE_RESOURCES] = "resources",
         [SCOPE_FAILURE_TIMEOUT]   = "timeout",
+        [SCOPE_FAILURE_OOM_KILL]  = "oom-kill",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
@@ -805,6 +833,7 @@ const UnitVTable scope_vtable = {
         .reset_failed = scope_reset_failed,
 
         .notify_cgroup_empty = scope_notify_cgroup_empty_event,
+        .notify_cgroup_oom = scope_notify_cgroup_oom_event,
 
         .bus_set_property = bus_scope_set_property,
         .bus_commit_properties = bus_scope_commit_properties,
index def1541652bc494cdd874a8cbe4dd007c01a85cc..6a228f1177d027d96370eb5a0faf03505275b9b2 100644 (file)
@@ -11,6 +11,7 @@ typedef enum ScopeResult {
         SCOPE_SUCCESS,
         SCOPE_FAILURE_RESOURCES,
         SCOPE_FAILURE_TIMEOUT,
+        SCOPE_FAILURE_OOM_KILL,
         _SCOPE_RESULT_MAX,
         _SCOPE_RESULT_INVALID = -EINVAL,
 } ScopeResult;
index ae1b47b2ba3d3437ce288ce3c1efc95fb4b2d92f..318c0348264f553bec0387681b2bab15588ceada 100644 (file)
@@ -46,6 +46,7 @@
 #DefaultTimeoutStartSec=90s
 #DefaultTimeoutStopSec=90s
 #DefaultTimeoutAbortSec=
+#DefaultDeviceTimeoutSec=90s
 #DefaultRestartSec=100ms
 #DefaultStartLimitIntervalSec=10s
 #DefaultStartLimitBurst=5
index 63256d541acfe0ef7b8bce69e3012e9d472fd8ac..9de325ba66240af365e0d9ca1b00d1187ed79373 100644 (file)
@@ -394,19 +394,18 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
                 if (v->base == TIMER_CALENDAR) {
                         usec_t b, rebased;
 
-                        /* If we know the last time this was
-                         * triggered, schedule the job based relative
-                         * to that. If we don't, just start from
-                         * the activation time. */
-
-                        if (t->last_trigger.realtime > 0)
+                        /* Update last_trigger to 'now' in case the system time changes, so that
+                         * next_elapse is not stuck with a future date. */
+                        if (time_change)
+                                b = ts.realtime;
+                        /* If we know the last time this was triggered, schedule the job based relative
+                         * to that. If we don't, just start from the activation time. */
+                        else if (t->last_trigger.realtime > 0)
                                 b = t->last_trigger.realtime;
-                        else {
-                                if (state_translation_table[t->state] == UNIT_ACTIVE)
-                                        b = UNIT(t)->inactive_exit_timestamp.realtime;
-                                else
-                                        b = ts.realtime;
-                        }
+                        else if (state_translation_table[t->state] == UNIT_ACTIVE)
+                                b = UNIT(t)->inactive_exit_timestamp.realtime;
+                        else
+                                b = ts.realtime;
 
                         r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
                         if (r < 0)
index 07c83c90a4c1e0aa9b8ae929f69407b962ea166a..0798c29c9d469f3a1f5038866a38154c64db74af 100644 (file)
@@ -5167,6 +5167,9 @@ void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) {
 
                                 unit_add_to_gc_queue(other);
 
+                                /* The unit 'other' may not be wanted by the unit 'u'. */
+                                unit_submit_to_stop_when_unneeded_queue(other);
+
                                 done = false;
                                 break;
                         }
index 59bb072115fe7a867275488bde53c3a7ca47804d..e9c7c96fc561065e58093d16afb02a64394a5b92 100644 (file)
@@ -832,13 +832,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_tpm2_device = streq(optarg, "auto") ? NULL : optarg;
                         break;
 
-                case ARG_TPM2_PCRS:
+                case ARG_TPM2_PCRS: {
+                        uint32_t mask;
+
                         if (isempty(optarg)) {
                                 arg_tpm2_pcr_mask = 0;
                                 break;
                         }
 
-                        uint32_t mask;
                         r = tpm2_parse_pcrs(optarg, &mask);
                         if (r < 0)
                                 return r;
@@ -849,6 +850,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 arg_tpm2_pcr_mask |= mask;
 
                         break;
+                }
 
                 case ARG_NAME:
                         if (isempty(optarg)) {
index 045adf871a1666d5ce76f1b4855bcd75ee81e80d..f7fc4963a83341ecf798fa6c4bf8a46287dc7077 100644 (file)
@@ -14,6 +14,7 @@
 #include "cryptsetup-util.h"
 #include "env-util.h"
 #include "escape.h"
+#include "fileio.h"
 #include "libfido2-util.h"
 #include "main-func.h"
 #include "memory-util.h"
@@ -28,6 +29,7 @@
 #include "tpm2-util.h"
 
 static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID;
+static char *arg_unlock_keyfile = NULL;
 static char *arg_pkcs11_token_uri = NULL;
 static char *arg_fido2_device = NULL;
 static char *arg_tpm2_device = NULL;
@@ -47,10 +49,12 @@ static int arg_fido2_cred_alg = 0;
 
 assert_cc(sizeof(arg_wipe_slots_mask) * 8 >= _ENROLL_TYPE_MAX);
 
+STATIC_DESTRUCTOR_REGISTER(arg_unlock_keyfile, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_node, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_wipe_slots, freep);
 
 static bool wipe_requested(void) {
         return arg_n_wipe_slots > 0 ||
@@ -92,6 +96,8 @@ static int help(void) {
                "     --version         Show package version\n"
                "     --password        Enroll a user-supplied password\n"
                "     --recovery-key    Enroll a recovery key\n"
+               "     --unlock-key-file=PATH\n"
+               "                       Use a file to unlock the volume\n"
                "     --pkcs11-token-uri=URI\n"
                "                       Specify PKCS#11 security token URI\n"
                "     --fido2-credential-algorithm=STRING\n"
@@ -127,6 +133,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERSION = 0x100,
                 ARG_PASSWORD,
                 ARG_RECOVERY_KEY,
+                ARG_UNLOCK_KEYFILE,
                 ARG_PKCS11_TOKEN_URI,
                 ARG_FIDO2_DEVICE,
                 ARG_TPM2_DEVICE,
@@ -144,6 +151,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",                      no_argument,       NULL, ARG_VERSION          },
                 { "password",                     no_argument,       NULL, ARG_PASSWORD         },
                 { "recovery-key",                 no_argument,       NULL, ARG_RECOVERY_KEY     },
+                { "unlock-key-file",              required_argument, NULL, ARG_UNLOCK_KEYFILE   },
                 { "pkcs11-token-uri",             required_argument, NULL, ARG_PKCS11_TOKEN_URI },
                 { "fido2-credential-algorithm",   required_argument, NULL, ARG_FIDO2_CRED_ALG   },
                 { "fido2-device",                 required_argument, NULL, ARG_FIDO2_DEVICE     },
@@ -221,6 +229,12 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_enroll_type = ENROLL_RECOVERY;
                         break;
 
+                case ARG_UNLOCK_KEYFILE:
+                        r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_unlock_keyfile);
+                        if (r < 0)
+                                return r;
+                        break;
+
                 case ARG_PKCS11_TOKEN_URI: {
                         _cleanup_free_ char *uri = NULL;
 
@@ -321,13 +335,12 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_TPM2_PIN: {
+                case ARG_TPM2_PIN:
                         r = parse_boolean_argument("--tpm2-with-pin=", optarg, &arg_tpm2_pin);
                         if (r < 0)
                                 return r;
 
                         break;
-                }
 
                 case ARG_WIPE_SLOT: {
                         const char *p = optarg;
@@ -473,6 +486,35 @@ static int prepare_luks(
         if (!vk)
                 return log_oom();
 
+        if (arg_unlock_keyfile) {
+                _cleanup_(erase_and_freep) char *password = NULL;
+                size_t password_len;
+
+                r = read_full_file_full(
+                                AT_FDCWD,
+                                arg_unlock_keyfile,
+                                0,
+                                SIZE_MAX,
+                                READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+                                NULL,
+                                &password,
+                                &password_len);
+                if (r < 0)
+                        return log_error_errno(r, "Reading keyfile %s failed: %m", arg_unlock_keyfile);
+
+                r = crypt_volume_key_get(
+                                cd,
+                                CRYPT_ANY_SLOT,
+                                vk,
+                                &vks,
+                                password,
+                                password_len);
+                if (r < 0)
+                        return log_error_errno(r, "Unlocking via keyfile failed: %m");
+
+                goto out;
+        }
+
         r = getenv_steal_erase("PASSWORD", &envpw);
         if (r < 0)
                 return log_error_errno(r, "Failed to acquire password from environment: %m");
@@ -536,6 +578,7 @@ static int prepare_luks(
                 }
         }
 
+out:
         *ret_cd = TAKE_PTR(cd);
         *ret_volume_key = TAKE_PTR(vk);
         *ret_volume_key_size = vks;
index 8f5ad67f48ee4b14ba4546ae84d112d6c91c5d18..07903f1044e7cb0524368c570ba639fa7f1f2c34 100644 (file)
@@ -227,9 +227,11 @@ static int generate_device_umount(const char *name,
         return 0;
 }
 
-static int print_dependencies(FILE *f, const char* device_path) {
+static int print_dependencies(FILE *f, const char* device_path, const char* timeout_value, bool canfail) {
         int r;
 
+        assert(!canfail || timeout_value);
+
         if (STR_IN_SET(device_path, "-", "none"))
                 /* None, nothing to do */
                 return 0;
@@ -259,9 +261,16 @@ static int print_dependencies(FILE *f, const char* device_path) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate unit name: %m");
 
-                fprintf(f,
-                        "After=%1$s\n"
-                        "Requires=%1$s\n", unit);
+                fprintf(f, "After=%1$s\n", unit);
+                if (canfail) {
+                        fprintf(f, "Wants=%1$s\n", unit);
+                        r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
+                                "# Automatically generated by systemd-cryptsetup-generator \n\n"
+                                "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to write device drop-in: %m");
+                } else
+                        fprintf(f, "Requires=%1$s\n", unit);
         } else {
                 /* Regular file, add mount dependency */
                 _cleanup_free_ char *escaped_path = specifier_escape(device_path);
@@ -463,14 +472,18 @@ static int create_disk(
                         netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
 
         if (key_file && !keydev) {
-                r = print_dependencies(f, key_file);
+                r = print_dependencies(f, key_file,
+                        keyfile_timeout_value,
+                        /* canfail= */ keyfile_can_timeout > 0);
                 if (r < 0)
                         return r;
         }
 
         /* Check if a header option was specified */
         if (detached_header > 0 && !headerdev) {
-                r = print_dependencies(f, header_path);
+                r = print_dependencies(f, header_path,
+                        NULL,
+                        /* canfail= */ false); /* header is always necessary */
                 if (r < 0)
                         return r;
         }
index 0db0f562e518093425eebe7c25bbaa589967b88c..30278040650066f8b8e01b2e7d3f4bc01c00f6b5 100644 (file)
@@ -43,18 +43,11 @@ _public_ int cryptsetup_token_open_pin(
         assert_se(token == r);
         assert(json);
 
-        if (pin && memchr(pin, 0, pin_size - 1))
-                return crypt_log_error_errno(cd, ENOANO, "PIN must be characters string.");
-
-        /* pin was passed as pin = pin, pin_size = strlen(pin). We need to add terminating
-         * NULL byte to addressable memory*/
-        if (pin && pin[pin_size-1] != '\0') {
-                pin_string = strndup(pin, pin_size);
-                if (!pin_string)
-                        return crypt_log_oom(cd);
-        }
+        r = crypt_normalize_pin(pin, pin_size, &pin_string);
+        if (r < 0)
+                return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
 
-        return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string ?: pin, password, password_len);
+        return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string, password, password_len);
 }
 
 /*
index 23df9749994783cb9e576c48a7106580a3ab22d1..bbc8a39c98b7d37e0caebbaf48ba9ab0744d0a6c 100644 (file)
@@ -35,22 +35,11 @@ static int log_debug_open_error(struct crypt_device *cd, int r) {
         return crypt_log_debug_errno(cd, r, TOKEN_NAME " open failed: %m.");
 }
 
-/*
- * This function is called from within following libcryptsetup calls
- * provided conditions further below are met:
- *
- * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
- *
- * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
- *   (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
- *    and token is assigned to at least single keyslot).
- *
- * - if plugin defines validate function (see cryptsetup_token_validate below) it must have
- *   passed the check (aka return 0)
- */
-_public_ int cryptsetup_token_open(
+_public_ int cryptsetup_token_open_pin(
                 struct crypt_device *cd, /* is always LUKS2 context */
                 int token /* is always >= 0 */,
+                const char *pin,
+                size_t pin_size,
                 char **password, /* freed by cryptsetup_token_buffer_free */
                 size_t *password_len,
                 void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
@@ -66,8 +55,9 @@ _public_ int cryptsetup_token_open(
         _cleanup_free_ void *blob = NULL, *policy_hash = NULL;
         _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
         _cleanup_(erase_and_freep) void *decrypted_key = NULL;
-        _cleanup_(erase_and_freep) char *base64_encoded = NULL;
+        _cleanup_(erase_and_freep) char *base64_encoded = NULL, *pin_string = NULL;
 
+        assert(!pin || pin_size);
         assert(password);
         assert(password_len);
         assert(token >= 0);
@@ -77,6 +67,10 @@ _public_ int cryptsetup_token_open(
         assert(token == r);
         assert(json);
 
+        r = crypt_normalize_pin(pin, pin_size, &pin_string);
+        if (r < 0)
+                return crypt_log_debug_errno(cd, r, "Can not normalize PIN: %m");
+
         if (usrptr)
                 params = *(systemd_tpm2_plugin_params *)usrptr;
 
@@ -105,6 +99,7 @@ _public_ int cryptsetup_token_open(
                         policy_hash,
                         policy_hash_size,
                         flags,
+                        pin_string,
                         &decrypted_key,
                         &decrypted_key_size);
         if (r < 0)
@@ -122,6 +117,29 @@ _public_ int cryptsetup_token_open(
         return 0;
 }
 
+/*
+ * This function is called from within following libcryptsetup calls
+ * provided conditions further below are met:
+ *
+ * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-tpm2'):
+ *
+ * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
+ *   (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
+ *    and token is assigned to at least single keyslot).
+ *
+ * - if plugin defines validate function (see cryptsetup_token_validate below) it must have
+ *   passed the check (aka return 0)
+ */
+_public_ int cryptsetup_token_open(
+                struct crypt_device *cd, /* is always LUKS2 context */
+                int token /* is always >= 0 */,
+                char **password, /* freed by cryptsetup_token_buffer_free */
+                size_t *password_len,
+                void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
+
+        return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
+}
+
 /*
  * libcryptsetup callback for memory deallocation of 'password' parameter passed in
  * any crypt_token_open_* plugin function
index f4086ae367b415ec9f58d7c63ee95813b2d9fc68..e305d8ba7958f8676adfafa3a085b8a426dca9b2 100644 (file)
@@ -56,3 +56,29 @@ int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str) {
 
         return 0;
 }
+
+int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string) {
+
+        _cleanup_free_ char *pin_string = NULL;
+
+        assert(pin || !pin_size);
+        assert(ret_pin_string);
+
+        if (!pin) {
+                *ret_pin_string = NULL;
+                return 0;
+        }
+
+        /* Refuse embedded NULL bytes, but allow trailing NULL */
+        if (memchr(pin, 0, pin_size - 1))
+                return -EINVAL;
+
+        /* Enforce trailing NULL byte if missing */
+        pin_string = memdup_suffix0(pin, pin_size);
+        if (!pin_string)
+                return -ENOMEM;
+
+        *ret_pin_string = TAKE_PTR(pin_string);
+
+        return 0;
+}
index 57ffca136f4740aa3528b4332b2d137c9c557b35..146beffb3054ce64bc7701af11ab914531591126 100644 (file)
@@ -36,3 +36,5 @@ int crypt_dump_buffer_to_hex_string(
                 char **ret_dump_str);
 
 int crypt_dump_hex_string(const char *hex_str, char **ret_dump_str);
+
+int crypt_normalize_pin(const void *pin, size_t pin_size, char **ret_pin_string);
index 0d6e4bc0f8c676a3ddf7a9a1f859701be27eb326..f0286ec1bf4f76864962a93e6fed17859c9b4c5b 100644 (file)
@@ -22,11 +22,11 @@ int acquire_luks2_key(
                 const void *policy_hash,
                 size_t policy_hash_size,
                 TPM2Flags flags,
+                const char *pin,
                 void **ret_decrypted_key,
                 size_t *ret_decrypted_key_size) {
 
         _cleanup_free_ char *auto_device = NULL;
-        _cleanup_(erase_and_freep) char *pin_str = NULL;
         int r;
 
         assert(ret_decrypted_key);
@@ -42,22 +42,15 @@ int acquire_luks2_key(
                 device = auto_device;
         }
 
-        r = getenv_steal_erase("PIN", &pin_str);
-        if (r < 0)
-                return log_error_errno(r, "Failed to acquire PIN from environment: %m");
-        if (!r) {
-                /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's
-                 * internal handling. */
-                if (flags & TPM2_FLAGS_USE_PIN)
-                        return -EOPNOTSUPP;
-        }
+        if ((flags & TPM2_FLAGS_USE_PIN) && !pin)
+                return -ENOANO;
 
         return tpm2_unseal(
                         device,
                         pcr_mask, pcr_bank,
                         primary_alg,
                         key_data, key_data_size,
-                        policy_hash, policy_hash_size, pin_str,
+                        policy_hash, policy_hash_size, pin,
                         ret_decrypted_key, ret_decrypted_key_size);
 }
 
index 34c93216eee18d14bf58a6244d4b8f9419fab406..5e3341802520354f227fb27484d1cba15655de36 100644 (file)
@@ -16,6 +16,7 @@ int acquire_luks2_key(
                 const void *policy_hash,
                 size_t policy_hash_size,
                 TPM2Flags flags,
+                const char *pin,
                 void **ret_decrypted_key,
                 size_t *ret_decrypted_key_size);
 
index da6d77b0b0795794281a72b0eac95b18938e2c4c..f0130eb238889bd027f9e921f140e7191a7d5d7a 100644 (file)
@@ -964,20 +964,24 @@ static int acquire_pins_from_env_variable(char ***ret_pins) {
 }
 #endif
 
-static int attach_luks2_by_fido2_via_plugin(
+static int crypt_activate_by_token_pin_ask_password(
                 struct crypt_device *cd,
                 const char *name,
+                const char *type,
                 usec_t until,
                 bool headless,
                 void *usrptr,
-                uint32_t activation_flags) {
+                uint32_t activation_flags,
+                const char *message,
+                const char *key_name,
+                const char *credential_name) {
 
 #if HAVE_LIBCRYPTSETUP_PLUGINS
         AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
         _cleanup_strv_free_erase_ char **pins = NULL;
         int r;
 
-        r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
+        r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
         if (r > 0) /* returns unlocked keyslot id on success */
                 r = 0;
         if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -988,7 +992,7 @@ static int attach_luks2_by_fido2_via_plugin(
                 return r;
 
         STRV_FOREACH(p, pins) {
-                r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+                r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
                 if (r > 0) /* returns unlocked keyslot id on success */
                         r = 0;
                 if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -1000,12 +1004,12 @@ static int attach_luks2_by_fido2_via_plugin(
 
         for (;;) {
                 pins = strv_free_erase(pins);
-                r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
+                r = ask_password_auto(message, "drive-harddisk", NULL, key_name, credential_name, until, flags, &pins);
                 if (r < 0)
                         return r;
 
                 STRV_FOREACH(p, pins) {
-                        r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+                        r = crypt_activate_by_token_pin(cd, name, type, CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
                         if (r > 0) /* returns unlocked keyslot id on success */
                                 r = 0;
                         if (r != -ENOANO) /* needs pin or pin is wrong */
@@ -1020,6 +1024,27 @@ static int attach_luks2_by_fido2_via_plugin(
 #endif
 }
 
+static int attach_luks2_by_fido2_via_plugin(
+                struct crypt_device *cd,
+                const char *name,
+                usec_t until,
+                bool headless,
+                void *usrptr,
+                uint32_t activation_flags) {
+
+        return crypt_activate_by_token_pin_ask_password(
+                        cd,
+                        name,
+                        "systemd-fido2",
+                        until,
+                        headless,
+                        usrptr,
+                        activation_flags,
+                        "Please enter security token PIN:",
+                        "fido2-pin",
+                        "cryptsetup.fido2-pin");
+}
+
 static int attach_luks_or_plain_or_bitlk_by_fido2(
                 struct crypt_device *cd,
                 const char *name,
@@ -1363,25 +1388,31 @@ static int make_tpm2_device_monitor(
 static int attach_luks2_by_tpm2_via_plugin(
                 struct crypt_device *cd,
                 const char *name,
+                usec_t until,
+                bool headless,
                 uint32_t flags) {
 
 #if HAVE_LIBCRYPTSETUP_PLUGINS
-        int r;
-
         systemd_tpm2_plugin_params params = {
                 .search_pcr_mask = arg_tpm2_pcr_mask,
                 .device = arg_tpm2_device
         };
 
-        if (!crypt_token_external_path())
+        if (!libcryptsetup_plugins_support())
                 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
                                        "Libcryptsetup has external plugins support disabled.");
 
-        r = crypt_activate_by_token_pin(cd, name, "systemd-tpm2", CRYPT_ANY_TOKEN, NULL, 0, &params, flags);
-        if (r > 0) /* returns unlocked keyslot id on success */
-                r = 0;
-
-        return r;
+        return crypt_activate_by_token_pin_ask_password(
+                        cd,
+                        name,
+                        "systemd-tpm2",
+                        until,
+                        headless,
+                        &params,
+                        flags,
+                        "Please enter TPM2 PIN:",
+                        "tpm2-pin",
+                        "cryptsetup.tpm2-pin");
 #else
         return -EOPNOTSUPP;
 #endif
@@ -1442,7 +1473,9 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
                                 return -EAGAIN; /* Mangle error code: let's make any form of TPM2 failure non-fatal. */
                         }
                 } else {
-                        r = attach_luks2_by_tpm2_via_plugin(cd, name, flags);
+                        r = attach_luks2_by_tpm2_via_plugin(cd, name, until, arg_headless, flags);
+                        if (r >= 0)
+                                return 0;
                         /* EAGAIN     means: no tpm2 chip found
                          * EOPNOTSUPP means: no libcryptsetup plugins support */
                         if (r == -ENXIO)
@@ -1966,8 +1999,18 @@ static int run(int argc, char *argv[]) {
                         }
 
                         /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
-                        if (!key_file && !key_data) {
-                                r = crypt_activate_by_token(cd, volume, CRYPT_ANY_TOKEN, NULL, flags);
+                        if (!key_file && !key_data && getenv_bool("SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE") != 0) {
+                                r = crypt_activate_by_token_pin_ask_password(
+                                                cd,
+                                                volume,
+                                                NULL,
+                                                until,
+                                                arg_headless,
+                                                NULL,
+                                                flags,
+                                                "Please enter LUKS2 token PIN:",
+                                                "luks2-pin",
+                                                "cryptsetup.luks2-pin");
                                 if (r >= 0) {
                                         log_debug("Volume %s activated with LUKS token id %i.", volume, r);
                                         return 0;
index 0716914b26f38bc9ddca8fa43748330f0a6fc1e5..9169129a6880776464d3e9dbcce3782c1102d4f5 100644 (file)
@@ -479,8 +479,9 @@ static int process_timezone(void) {
                                 return log_error_errno(r, "Failed to read host timezone: %m");
 
                         (void) mkdir_parents(etc_localtime, 0755);
-                        if (symlink(p, etc_localtime) < 0)
-                                return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
+                        r = symlink_atomic(p, etc_localtime);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to create %s symlink: %m", etc_localtime);
 
                         log_info("%s copied.", etc_localtime);
                         return 0;
@@ -497,8 +498,9 @@ static int process_timezone(void) {
         e = strjoina("../usr/share/zoneinfo/", arg_timezone);
 
         (void) mkdir_parents(etc_localtime, 0755);
-        if (symlink(e, etc_localtime) < 0)
-                return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
+        r = symlink_atomic(e, etc_localtime);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create %s symlink: %m", etc_localtime);
 
         log_info("%s written", etc_localtime);
         return 0;
@@ -595,21 +597,8 @@ static int prompt_root_password(void) {
         if (arg_root_password)
                 return 0;
 
-        r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
-        if (r == -ENOENT) {
-                r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
-                if (r < 0)
-                        log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
-                else {
-                        arg_root_password_is_hashed = false;
-                        return 0;
-                }
-        } else if (r < 0)
-                log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
-        else {
-                arg_root_password_is_hashed = true;
+        if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
                 return 0;
-        }
 
         if (!arg_prompt_root_password)
                 return 0;
index b7fe729836e3c20a9bfd4ea352ed5ef0c05bc79f..f5f8a10c5701d31485c76745a742d2b224f6e8fc 100644 (file)
@@ -52,7 +52,7 @@ static void start_target(const char *target, const char *mode) {
                 return;
         }
 
-        log_info("Running request %s/start/%s", target, mode);
+        log_info("Requesting %s/start/%s", target, mode);
 
         /* Start this unit only if we can replace basic.target with it */
         r = sd_bus_call_method(bus,
index da7ea627f1536c1aa5100e00ddb29f0d9cec9240..e76de45a0faaa6e2b360010188d159ff4e1684cd 100644 (file)
@@ -5,6 +5,8 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-locator.h"
 #include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -20,6 +22,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
+#include "process-util.h"
 #include "special.h"
 #include "specifier.h"
 #include "stat-util.h"
@@ -39,6 +42,7 @@ typedef enum MountPointFlags {
         MOUNT_RW_ONLY   = 1 << 5,
 } MountPointFlags;
 
+static bool arg_sysroot_check = false;
 static const char *arg_dest = NULL;
 static const char *arg_dest_late = NULL;
 static bool arg_fstab_enabled = true;
@@ -119,6 +123,11 @@ static int add_swap(
                 return 0;
         }
 
+        if (arg_sysroot_check) {
+                log_info("%s should be enabled in the initrd, will request daemon-reload.", what);
+                return true;
+        }
+
         r = unit_name_from_path(what, ".swap", &name);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate unit name: %m");
@@ -175,7 +184,7 @@ static int add_swap(
                         return r;
         }
 
-        return 0;
+        return true;
 }
 
 static bool mount_is_network(struct mntent *me) {
@@ -378,6 +387,11 @@ static int add_mount(
             mount_point_ignore(where))
                 return 0;
 
+        if (arg_sysroot_check) {
+                log_info("%s should be mounted in the initrd, will request daemon-reload.", where);
+                return true;
+        }
+
         r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
         if (r < 0)
                 return r;
@@ -567,7 +581,52 @@ static int add_mount(
                         return r;
         }
 
-        return 0;
+        return true;
+}
+
+static int do_daemon_reload(void) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r, k;
+
+        log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
+
+        r = bus_connect_system_systemd(&bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+        /* We need to requeue the two targets so that any new units which previously were not part of the
+         * targets, and which we now added, will be started. */
+
+        r = 0;
+        FOREACH_STRING(unit, SPECIAL_INITRD_FS_TARGET, SPECIAL_SWAP_TARGET) {
+                log_info("Requesting %s/start/replace...", unit);
+
+                k = sd_bus_call_method(bus,
+                                       "org.freedesktop.systemd1",
+                                       "/org/freedesktop/systemd1",
+                                       "org.freedesktop.systemd1.Manager",
+                                       "StartUnit",
+                                       &error,
+                                       NULL,
+                                       "ss", unit, "replace");
+                if (k < 0) {
+                        log_error_errno(k, "Failed to (re)start %s: %s", unit, bus_error_message(&error, r));
+                        if (r == 0)
+                                r = k;
+                }
+        }
+
+        return r;
 }
 
 static const char* sysroot_fstab_path(void) {
@@ -582,8 +641,10 @@ static int parse_fstab(bool initrd) {
 
         if (initrd)
                 fstab = sysroot_fstab_path();
-        else
+        else {
                 fstab = fstab_path();
+                assert(!arg_sysroot_check);
+        }
 
         log_debug("Parsing %s...", fstab);
 
@@ -700,6 +761,8 @@ static int parse_fstab(bool initrd) {
                                       target_unit);
                 }
 
+                if (arg_sysroot_check && k > 0)
+                        return true;  /* We found a mount or swap that would be started… */
                 if (r >= 0 && k < 0)
                         r = k;
         }
@@ -1126,12 +1189,14 @@ static int determine_usr(void) {
         return determine_device(&arg_usr_what, arg_usr_hash, "usr");
 }
 
-static int run(const char *dest, const char *dest_early, const char *dest_late) {
+/* If arg_sysroot_check is false, run as generator in the usual fashion.
+ * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
+ * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
+ * with /sysroot/etc/fstab available, and then we can write additional units based
+ * on that file. */
+static int run_generator(void) {
         int r, r2 = 0, r3 = 0;
 
-        assert_se(arg_dest = dest);
-        assert_se(arg_dest_late = dest_late);
-
         r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@@ -1139,6 +1204,15 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         (void) determine_root();
         (void) determine_usr();
 
+        if (arg_sysroot_check) {
+                r = parse_fstab(true);
+                if (r == 0)
+                        log_debug("Nothing interesting found, not doing daemon-reload.");
+                if (r > 0)
+                        r = do_daemon_reload();
+                return r;
+        }
+
         /* Always honour root= and usr= in the kernel command line if we are in an initrd */
         if (in_initrd()) {
                 r = add_sysroot_mount();
@@ -1164,4 +1238,32 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         return r < 0 ? r : r2 < 0 ? r2 : r3;
 }
 
-DEFINE_MAIN_GENERATOR_FUNCTION(run);
+static int run(int argc, char **argv) {
+        arg_sysroot_check = invoked_as(argv, "systemd-sysroot-fstab-check");
+
+        if (arg_sysroot_check) {
+                /* Run as in systemd-sysroot-fstab-check mode */
+                log_setup();
+
+                if (strv_length(argv) > 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program takes no arguments.");
+                if (!in_initrd())
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program is only useful in the initrd.");
+        } else {
+                /* Run in generator mode */
+                log_setup_generator();
+
+                if (!IN_SET(strv_length(argv), 2, 4))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program takes one or three arguments.");
+
+                arg_dest = ASSERT_PTR(argv[1]);
+                arg_dest_late = ASSERT_PTR(argv[argc > 3 ? 3 : 1]);
+        }
+
+        return run_generator();
+}
+
+DEFINE_MAIN_FUNCTION(run);
index 33e1a20de6f9e776cfacca81e0b7902cf71b7258..fa56a8322d4d34bd67200d03f17dafe9283634b8 100644 (file)
@@ -53,7 +53,8 @@ static int open_parent_block_device(dev_t devnum, int *ret_fd) {
 
         r = sd_device_new_from_devnum(&d, 'b', devnum);
         if (r < 0)
-                return log_debug_errno(r, "Failed to open device: %m");
+                return log_debug_errno(r, "Failed to create device object for block device "DEVNUM_FORMAT_STR": %m",
+                                       DEVNUM_FORMAT_VAL(devnum));
 
         if (sd_device_get_devname(d, &name) < 0) {
                 r = sd_device_get_syspath(d, &name);
index a48a8570c47ea27b6ae9e598bd5ad0e1268a492a..52b1ba199a177aeb905d67deba7e3eebd0fac31c 100644 (file)
@@ -103,7 +103,7 @@ static int change_runlevel(Server *s, int runlevel) {
         else
                 mode = "replace-irreversibly";
 
-        log_debug("Running request %s/start/%s", target, mode);
+        log_debug("Requesting %s/start/%s", target, mode);
 
         r = sd_bus_call_method(
                         s->bus,
index 954e154f574ab9bf6c89be8fff9db74fd4544eb4..e7afbd3eb3aa23a1e8ad05280bf5f58e4ac04401 100644 (file)
@@ -1746,7 +1746,7 @@ static int server_parse_config_file(Server *s) {
                                 dropin_dirname,
                                 "Journal\0",
                                 config_item_perf_lookup, journald_gperf_lookup,
-                                CONFIG_PARSE_WARN, s, NULL);
+                                CONFIG_PARSE_WARN, s, NULL, NULL);
                 if (r < 0)
                         return r;
 
index 326b09ac5e20cc42a9ff6c11a6e9c6ce06388513..68f6a7cb3c040845c28668374b5913c2b80026e3 100644 (file)
@@ -63,20 +63,26 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) {
         return 0;
 }
 
-static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) {
+static int dhcp_identifier_set_duid_llt(
+                const struct hw_addr_data *hw_addr,
+                uint16_t arp_type,
+                usec_t t,
+                struct duid *ret_duid,
+                size_t *ret_len) {
+
         uint16_t time_from_2000y;
 
-        assert(addr);
+        assert(hw_addr);
         assert(ret_duid);
         assert(ret_len);
 
-        if (addr_len == 0)
+        if (hw_addr->length == 0)
                 return -EOPNOTSUPP;
 
         if (arp_type == ARPHRD_ETHER)
-                assert_return(addr_len == ETH_ALEN, -EINVAL);
+                assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
         else if (arp_type == ARPHRD_INFINIBAND)
-                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
+                assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
         else
                 return -EOPNOTSUPP;
 
@@ -88,33 +94,38 @@ static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, ui
         unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT);
         unaligned_write_be16(&ret_duid->llt.htype, arp_type);
         unaligned_write_be32(&ret_duid->llt.time, time_from_2000y);
-        memcpy(ret_duid->llt.haddr, addr, addr_len);
+        memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length);
 
-        *ret_len = offsetof(struct duid, llt.haddr) + addr_len;
+        *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length;
 
         return 0;
 }
 
-static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) {
-        assert(addr);
+static int dhcp_identifier_set_duid_ll(
+                const struct hw_addr_data *hw_addr,
+                uint16_t arp_type,
+                struct duid *ret_duid,
+                size_t *ret_len) {
+
+        assert(hw_addr);
         assert(ret_duid);
         assert(ret_len);
 
-        if (addr_len == 0)
+        if (hw_addr->length == 0)
                 return -EOPNOTSUPP;
 
         if (arp_type == ARPHRD_ETHER)
-                assert_return(addr_len == ETH_ALEN, -EINVAL);
+                assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
         else if (arp_type == ARPHRD_INFINIBAND)
-                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
+                assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
         else
                 return -EOPNOTSUPP;
 
         unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL);
         unaligned_write_be16(&ret_duid->ll.htype, arp_type);
-        memcpy(ret_duid->ll.haddr, addr, addr_len);
+        memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length);
 
-        *ret_len = offsetof(struct duid, ll.haddr) + addr_len;
+        *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length;
 
         return 0;
 }
@@ -174,8 +185,7 @@ static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len)
 
 int dhcp_identifier_set_duid(
                 DUIDType duid_type,
-                const uint8_t *addr,
-                size_t addr_len,
+                const struct hw_addr_data *hw_addr,
                 uint16_t arp_type,
                 usec_t llt_time,
                 bool test_mode,
@@ -184,11 +194,11 @@ int dhcp_identifier_set_duid(
 
         switch (duid_type) {
         case DUID_TYPE_LLT:
-                return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len);
+                return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len);
         case DUID_TYPE_EN:
                 return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len);
         case DUID_TYPE_LL:
-                return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len);
+                return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len);
         case DUID_TYPE_UUID:
                 return dhcp_identifier_set_duid_uuid(ret_duid, ret_len);
         default:
@@ -198,8 +208,7 @@ int dhcp_identifier_set_duid(
 
 int dhcp_identifier_set_iaid(
                 int ifindex,
-                const uint8_t *mac,
-                size_t mac_len,
+                const struct hw_addr_data *hw_addr,
                 bool legacy_unstable_byteorder,
                 bool use_mac,
                 void *ret) {
@@ -212,6 +221,10 @@ int dhcp_identifier_set_iaid(
         uint64_t id;
         int r;
 
+        assert(ifindex > 0);
+        assert(hw_addr);
+        assert(ret);
+
         if (udev_available() && !use_mac) {
                 /* udev should be around */
 
@@ -240,7 +253,7 @@ int dhcp_identifier_set_iaid(
                 id = siphash24(name, strlen(name), HASH_KEY.bytes);
         else
                 /* fall back to MAC address if no predictable name available */
-                id = siphash24(mac, mac_len, HASH_KEY.bytes);
+                id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
 
         id32 = (id & 0xffffffff) ^ (id >> 32);
 
index 697ba3bfbb0d28d77a4841ca546cfca6333e43d2..8acb8c3210a94a7a18706791029344bdc7b26ce8 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sd-id128.h"
 
+#include "ether-addr-util.h"
 #include "macro.h"
 #include "sparse-endian.h"
 #include "time-util.h"
@@ -58,8 +59,7 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict);
 int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len);
 int dhcp_identifier_set_duid(
                 DUIDType duid_type,
-                const uint8_t *addr,
-                size_t addr_len,
+                const struct hw_addr_data *hw_addr,
                 uint16_t arp_type,
                 usec_t llt_time,
                 bool test_mode,
@@ -67,8 +67,7 @@ int dhcp_identifier_set_duid(
                 size_t *ret_len);
 int dhcp_identifier_set_iaid(
                 int ifindex,
-                const uint8_t *mac,
-                size_t mac_len,
+                const struct hw_addr_data *hw_addr,
                 bool legacy_unstable_byteorder,
                 bool use_mac,
                 void *ret);
index 466d8e4b3f1403f4889ef1f3a5a7d77802d9ab65..a311d1d5b9129d3d150ee4338e7b66292d33d26f 100644 (file)
@@ -12,6 +12,7 @@
 #include "sd-dhcp-client.h"
 
 #include "dhcp-protocol.h"
+#include "ether-addr-util.h"
 #include "network-common.h"
 #include "socket-util.h"
 
@@ -32,10 +33,14 @@ extern const struct hash_ops dhcp_option_hash_ops;
 
 typedef struct sd_dhcp_client sd_dhcp_client;
 
-int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
-                                 const uint8_t *mac_addr, size_t mac_addr_len,
-                                 const uint8_t *bcast_addr, size_t bcast_addr_len,
-                                 uint16_t arp_type, uint16_t port);
+int dhcp_network_bind_raw_socket(
+                int ifindex,
+                union sockaddr_union *link,
+                uint32_t xid,
+                const struct hw_addr_data *hw_addr,
+                const struct hw_addr_data *bcast_addr,
+                uint16_t arp_type,
+                uint16_t port);
 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
index 7abdaa515bcf6d9d18ab5f90a043fb332bdf5e60..0ee977a8c82c77a4795c29f6db617cdd0d74b0c1 100644 (file)
 #include "socket-util.h"
 #include "unaligned.h"
 
-static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
-                            uint32_t xid,
-                            const uint8_t *bcast_addr,
-                            size_t bcast_addr_len,
-                            const struct ether_addr *eth_mac,
-                            uint16_t arp_type, uint8_t dhcp_hlen,
-                            uint16_t port) {
+static int _bind_raw_socket(
+                int ifindex,
+                union sockaddr_union *link,
+                uint32_t xid,
+                const struct hw_addr_data *hw_addr,
+                const struct hw_addr_data *bcast_addr,
+                uint16_t arp_type,
+                uint16_t port) {
+
+        assert(ifindex > 0);
+        assert(link);
+        assert(hw_addr);
+        assert(bcast_addr);
+        assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
+
+        switch (arp_type) {
+        case ARPHRD_ETHER:
+                assert(hw_addr->length == ETH_ALEN);
+                assert(bcast_addr->length == ETH_ALEN);
+                break;
+        case ARPHRD_INFINIBAND:
+                assert(hw_addr->length == 0);
+                assert(bcast_addr->length == INFINIBAND_ALEN);
+                break;
+        default:
+                assert_not_reached();
+        }
+
         struct sock_filter filter[] = {
                 BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
                 BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
@@ -53,20 +74,20 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- MAC address length */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (uint8_t) hw_addr->length, 1, 0),  /* address length == hw_addr->length ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
 
                 /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
                  * compare chaddr for ETH_ALEN bytes. */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8),                                   /* A (the MAC address length) == ETH_ALEN ? */
-                BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])),       /* X <- 4 bytes of client's MAC */
-                BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0),                                          /* A == X ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
-                BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])),       /* X <- remainder of client's MAC */
-                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),             /* A <- remainder of MAC from dhcp.chaddr */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0),                                          /* A == X ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8),                        /* A (the MAC address length) == ETH_ALEN ? */
+                BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(hw_addr->bytes)),           /* X <- 4 bytes of client's MAC */
+                BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),      /* A <- 4 bytes of MAC from dhcp.chaddr */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0),                               /* A == X ? */
+                BPF_STMT(BPF_RET + BPF_K, 0),                                               /* ignore */
+                BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(hw_addr->bytes + 4)),       /* X <- remainder of client's MAC */
+                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),  /* A <- remainder of MAC from dhcp.chaddr */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0),                               /* A == X ? */
+                BPF_STMT(BPF_RET + BPF_K, 0),                                               /* ignore */
 
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
@@ -80,9 +101,6 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
         _cleanup_close_ int s = -1;
         int r;
 
-        assert(ifindex > 0);
-        assert(link);
-
         s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
         if (s < 0)
                 return -errno;
@@ -100,9 +118,10 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
                 .sll_protocol = htobe16(ETH_P_IP),
                 .sll_ifindex = ifindex,
                 .sll_hatype = htobe16(arp_type),
-                .sll_halen = bcast_addr_len,
+                .sll_halen = bcast_addr->length,
         };
-        memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
+        /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
+        memcpy(link->ll.sll_addr, bcast_addr->bytes, bcast_addr->length);
 
         r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
         if (r < 0)
@@ -115,47 +134,42 @@ int dhcp_network_bind_raw_socket(
                 int ifindex,
                 union sockaddr_union *link,
                 uint32_t xid,
-                const uint8_t *mac_addr,
-                size_t mac_addr_len,
-                const uint8_t *bcast_addr,
-                size_t bcast_addr_len,
+                const struct hw_addr_data *hw_addr,
+                const struct hw_addr_data *bcast_addr,
                 uint16_t arp_type,
                 uint16_t port) {
 
-        static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-        /* Default broadcast address for IPoIB */
-        static const uint8_t ib_bcast[] = {
-                0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0xff, 0xff, 0xff, 0xff
+        static struct hw_addr_data default_eth_bcast = {
+                .length = ETH_ALEN,
+                .ether = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+        }, default_ib_bcast = {
+                .length = INFINIBAND_ALEN,
+                .infiniband = {
+                        0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
+                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                        0xff, 0xff, 0xff, 0xff
+                },
         };
-        struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
-        const uint8_t *default_bcast_addr;
-        size_t expected_bcast_addr_len;
-        uint8_t dhcp_hlen = 0;
-
-        if (arp_type == ARPHRD_ETHER) {
-                assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
-                memcpy(&eth_mac, mac_addr, ETH_ALEN);
-                dhcp_hlen = ETH_ALEN;
-
-                default_bcast_addr = eth_bcast;
-                expected_bcast_addr_len = ETH_ALEN;
-        } else if (arp_type == ARPHRD_INFINIBAND) {
-                default_bcast_addr = ib_bcast;
-                expected_bcast_addr_len = INFINIBAND_ALEN;
-        } else
-                return -EINVAL;
 
-        if (bcast_addr && bcast_addr_len > 0)
-                assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
-        else {
-                bcast_addr = default_bcast_addr;
-                bcast_addr_len = expected_bcast_addr_len;
+        assert(ifindex > 0);
+        assert(link);
+        assert(hw_addr);
+
+        switch (arp_type) {
+        case ARPHRD_ETHER:
+                return _bind_raw_socket(ifindex, link, xid,
+                                        hw_addr,
+                                        (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_eth_bcast,
+                                        arp_type, port);
+
+        case ARPHRD_INFINIBAND:
+                return _bind_raw_socket(ifindex, link, xid,
+                                        &HW_ADDR_NULL,
+                                        (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_ib_bcast,
+                                        arp_type, port);
+        default:
+                return -EINVAL;
         }
-
-        return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
-                                &eth_mac, arp_type, dhcp_hlen, port);
 }
 
 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
index dd54bcf6ee933842049b15047a43de1583b5f370..c4972d144c238c2cff5d708a8846278d50f483c0 100644 (file)
@@ -43,9 +43,10 @@ typedef struct DHCPPacket DHCPPacket;
 
 #define DHCP_IP_SIZE            (int32_t)(sizeof(struct iphdr))
 #define DHCP_IP_UDP_SIZE        (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
-#define DHCP_MESSAGE_SIZE       (int32_t)(sizeof(DHCPMessage))
-#define DHCP_DEFAULT_MIN_SIZE   576 /* the minimum internet hosts must be able to receive */
-#define DHCP_MIN_OPTIONS_SIZE   (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE)
+#define DHCP_HEADER_SIZE        (int32_t)(sizeof(DHCPMessage))
+#define DHCP_MIN_MESSAGE_SIZE   576 /* the minimum internet hosts must be able to receive, see RFC 2132 Section 9.10 */
+#define DHCP_MIN_OPTIONS_SIZE   (DHCP_MIN_MESSAGE_SIZE - DHCP_HEADER_SIZE)
+#define DHCP_MIN_PACKET_SIZE    (DHCP_MIN_MESSAGE_SIZE + DHCP_IP_UDP_SIZE)
 #define DHCP_MAGIC_COOKIE       (uint32_t)(0x63825363)
 
 enum {
index c399a7ac50e2b1cb25b22230942541242ca1cbc3..f965ea40fea9c882ccc6f0c68f441d154ede7a23 100644 (file)
@@ -82,3 +82,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
+
+int dhcp6_message_status_to_errno(DHCP6Status s) {
+        switch (s) {
+        case DHCP6_STATUS_SUCCESS:
+                return 0;
+        case DHCP6_STATUS_NO_BINDING:
+                return -EADDRNOTAVAIL;
+        default:
+                return -EINVAL;
+        }
+}
index f4e47857e3e97137254f421bc380ad6ddd40a7e7..18217691b7511afd8ccce48dd420bb1c4e42c89b 100644 (file)
@@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_;
 DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
 const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
 DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
+int dhcp6_message_status_to_errno(DHCP6Status s);
index 1812a61950ec9cbf52a8ad09943eb9a37a7c35f6..a9cfba90e3d769f9242b44c6523ab96769dab192 100644 (file)
@@ -14,8 +14,8 @@ int dhcp_network_bind_raw_socket(
                 int ifindex,
                 union sockaddr_union *link,
                 uint32_t id,
-                const uint8_t *addr, size_t addr_len,
-                const uint8_t *bcaddr, size_t bcaddr_len,
+                const struct hw_addr_data *hw_addr,
+                const struct hw_addr_data *bcast_addr,
                 uint16_t arp_type, uint16_t port) {
 
         int fd;
index 3b53c5c6a80d98320ed9c12dca69879b75c5f4cd..a1c34365c0301dbcd80e038da770da091b5932ab 100644 (file)
@@ -48,7 +48,7 @@ static void fuzz_client(sd_dhcp6_client *client, const uint8_t *data, size_t siz
                         assert_se(IN_SET(client->state, DHCP6_STATE_REQUEST, DHCP6_STATE_BOUND));
                         break;
                 case DHCP6_STATE_REQUEST:
-                        assert_se(client->state == DHCP6_STATE_BOUND);
+                        assert_se(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_SOLICITATION));
                         break;
                 default:
                         assert_not_reached();
index d2c6361cb85510e4c7b26f4cfe0e4a1700cdcc4f..5b7e3640e87f7a181ee8043f9668ccaf00f893b3 100644 (file)
@@ -19,6 +19,7 @@
 #include "dhcp-lease-internal.h"
 #include "dhcp-protocol.h"
 #include "dns-domain.h"
+#include "ether-addr-util.h"
 #include "event-util.h"
 #include "fd-util.h"
 #include "hostname-util.h"
@@ -86,10 +87,8 @@ struct sd_dhcp_client {
         Set *req_opts;
         bool anonymize;
         be32_t last_addr;
-        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
-        size_t mac_addr_len;
-        uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
-        size_t bcast_addr_len;
+        struct hw_addr_data hw_addr;
+        struct hw_addr_data bcast_addr;
         uint16_t arp_type;
         sd_dhcp_client_id client_id;
         size_t client_id_len;
@@ -237,6 +236,7 @@ int sd_dhcp_client_set_callback(
 
 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         client->request_broadcast = broadcast;
 
@@ -245,7 +245,7 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast)
 
 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
         assert_return(client, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         switch (option) {
 
@@ -268,7 +268,7 @@ int sd_dhcp_client_set_request_address(
                 const struct in_addr *last_addr) {
 
         assert_return(client, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         if (last_addr)
                 client->last_addr = last_addr->s_addr;
@@ -280,7 +280,7 @@ int sd_dhcp_client_set_request_address(
 
 int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
         assert_return(client, -EINVAL);
-        assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(ifindex > 0, -EINVAL);
 
         client->ifindex = ifindex;
@@ -314,54 +314,20 @@ int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret) {
 
 int sd_dhcp_client_set_mac(
                 sd_dhcp_client *client,
-                const uint8_t *addr,
+                const uint8_t *hw_addr,
                 const uint8_t *bcast_addr,
                 size_t addr_len,
                 uint16_t arp_type) {
 
-        DHCP_CLIENT_DONT_DESTROY(client);
-        bool need_restart = false;
-        int r;
-
         assert_return(client, -EINVAL);
-        assert_return(addr, -EINVAL);
-        assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
-        assert_return(arp_type > 0, -EINVAL);
-
-        if (arp_type == ARPHRD_ETHER)
-                assert_return(addr_len == ETH_ALEN, -EINVAL);
-        else if (arp_type == ARPHRD_INFINIBAND)
-                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
-        else
-                return -EINVAL;
-
-        if (client->mac_addr_len == addr_len &&
-            memcmp(&client->mac_addr, addr, addr_len) == 0 &&
-            (client->bcast_addr_len > 0) == !!bcast_addr &&
-            (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
-                return 0;
-
-        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
-                log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
-                need_restart = true;
-                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
-        }
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
+        assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND), -EINVAL);
+        assert_return(hw_addr, -EINVAL);
+        assert_return(addr_len == (arp_type == ARPHRD_ETHER ? ETH_ALEN : INFINIBAND_ALEN), -EINVAL);
 
-        memcpy(&client->mac_addr, addr, addr_len);
-        client->mac_addr_len = addr_len;
         client->arp_type = arp_type;
-        client->bcast_addr_len = 0;
-
-        if (bcast_addr) {
-                memcpy(&client->bcast_addr, bcast_addr, addr_len);
-                client->bcast_addr_len = addr_len;
-        }
-
-        if (need_restart && client->state != DHCP_STATE_STOPPED) {
-                r = sd_dhcp_client_start(client);
-                if (r < 0)
-                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
-        }
+        hw_addr_set(&client->hw_addr, hw_addr, addr_len);
+        hw_addr_set(&client->bcast_addr, bcast_addr, bcast_addr ? addr_len : 0);
 
         return 0;
 }
@@ -396,19 +362,11 @@ int sd_dhcp_client_set_client_id(
                 const uint8_t *data,
                 size_t data_len) {
 
-        DHCP_CLIENT_DONT_DESTROY(client);
-        bool need_restart = false;
-        int r;
-
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(data, -EINVAL);
         assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
 
-        if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
-            client->client_id.type == type &&
-            memcmp(&client->client_id.raw.data, data, data_len) == 0)
-                return 0;
-
         /* For hardware types, log debug message about unexpected data length.
          *
          * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
@@ -420,23 +378,10 @@ int sd_dhcp_client_set_client_id(
                                 "unexpected address length %zu",
                                 type, data_len);
 
-        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
-                log_dhcp_client(client, "Changing client ID on running DHCP "
-                                "client, restarting");
-                need_restart = true;
-                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
-        }
-
         client->client_id.type = type;
         memcpy(&client->client_id.raw.data, data, data_len);
         client->client_id_len = data_len + sizeof (client->client_id.type);
 
-        if (need_restart && client->state != DHCP_STATE_STOPPED) {
-                r = sd_dhcp_client_start(client);
-                if (r < 0)
-                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
-        }
-
         return 0;
 }
 
@@ -455,11 +400,11 @@ static int dhcp_client_set_iaid_duid_internal(
                 size_t duid_len,
                 usec_t llt_time) {
 
-        DHCP_CLIENT_DONT_DESTROY(client);
-        int r;
         size_t len;
+        int r;
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(duid_len == 0 || duid, -EINVAL);
 
         if (duid) {
@@ -475,8 +420,7 @@ static int dhcp_client_set_iaid_duid_internal(
                 if (iaid_set)
                         client->client_id.ns.iaid = htobe32(iaid);
                 else {
-                        r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
-                                                     client->mac_addr_len,
+                        r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
                                                      /* legacy_unstable_byteorder = */ true,
                                                      /* use_mac = */ client->test_mode,
                                                      &client->client_id.ns.iaid);
@@ -491,7 +435,7 @@ static int dhcp_client_set_iaid_duid_internal(
                 len = sizeof(client->client_id.ns.duid.type) + duid_len;
 
         } else {
-                r = dhcp_identifier_set_duid(duid_type, client->mac_addr, client->mac_addr_len,
+                r = dhcp_identifier_set_duid(duid_type, &client->hw_addr,
                                              client->arp_type, llt_time, client->test_mode,
                                              &client->client_id.ns.duid, &len);
                 if (r == -EOPNOTSUPP)
@@ -507,14 +451,6 @@ static int dhcp_client_set_iaid_duid_internal(
         client->client_id_len = sizeof(client->client_id.type) + len +
                                 (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
 
-        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
-                log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
-                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
-                r = sd_dhcp_client_start(client);
-                if (r < 0)
-                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
-        }
-
         return 0;
 }
 
@@ -561,6 +497,7 @@ int sd_dhcp_client_set_hostname(
                 const char *hostname) {
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         /* Make sure hostnames qualify as DNS and as Linux hostnames */
         if (hostname &&
@@ -575,6 +512,7 @@ int sd_dhcp_client_set_vendor_class_identifier(
                 const char *vci) {
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         return free_and_strdup(&client->vendor_class_identifier, vci);
 }
@@ -584,6 +522,7 @@ int sd_dhcp_client_set_mud_url(
                 const char *mudurl) {
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(mudurl, -EINVAL);
         assert_return(strlen(mudurl) <= 255, -EINVAL);
         assert_return(http_url_is_valid(mudurl), -EINVAL);
@@ -598,6 +537,7 @@ int sd_dhcp_client_set_user_class(
         char **s = NULL;
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(!strv_isempty(user_class), -EINVAL);
 
         STRV_FOREACH(p, user_class) {
@@ -619,6 +559,7 @@ int sd_dhcp_client_set_client_port(
                 uint16_t port) {
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         client->port = port;
 
@@ -627,7 +568,10 @@ int sd_dhcp_client_set_client_port(
 
 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
         assert_return(client, -EINVAL);
-        assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
+        assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE);
+
+        /* MTU may be changed by the acquired lease. Hence, we cannot require that the client is stopped here.
+         * Please do not add assertion for !sd_dhcp_client_is_running(client) here. */
 
         client->mtu = mtu;
 
@@ -636,6 +580,7 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
 
 int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         client->max_attempts = max_attempts;
 
@@ -646,6 +591,7 @@ int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
         int r;
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(v, -EINVAL);
 
         r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v);
@@ -660,6 +606,7 @@ int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v)
         int r;
 
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(v, -EINVAL);
 
         r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
@@ -689,6 +636,7 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
 
 int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         client->ip_service_type = type;
 
@@ -697,6 +645,7 @@ int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
 
 int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
         assert_return(fallback_lease_lifetime > 0, -EINVAL);
 
         client->fallback_lease_lifetime = fallback_lease_lifetime;
@@ -794,7 +743,6 @@ static int client_message_init(
 
         _cleanup_free_ DHCPPacket *packet = NULL;
         size_t optlen, optoffset, size;
-        be16_t max_size;
         usec_t time_now;
         uint16_t secs;
         int r;
@@ -814,7 +762,7 @@ static int client_message_init(
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
-                              client->arp_type, client->mac_addr_len, client->mac_addr,
+                              client->arp_type, client->hw_addr.length, client->hw_addr.bytes,
                               optlen, &optoffset);
         if (r < 0)
                 return r;
@@ -851,7 +799,7 @@ static int client_message_init(
 
                 client->client_id.type = 255;
 
-                r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
+                r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
                                              /* legacy_unstable_byteorder = */ true,
                                              /* use_mac = */ client->test_mode,
                                              &client->client_id.ns.iaid);
@@ -937,9 +885,9 @@ static int client_message_init(
          */
         /* RFC7844 section 3:
            SHOULD NOT contain any other option. */
-        if (!client->anonymize && type != DHCP_RELEASE) {
-                max_size = htobe16(size);
-                r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
+        if (!client->anonymize && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) {
+                be16_t max_size = htobe16(MIN(client->mtu - DHCP_IP_UDP_SIZE, (uint32_t) UINT16_MAX));
+                r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
                                        SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
                                        2, &max_size);
                 if (r < 0)
@@ -1430,8 +1378,7 @@ static int client_start_delayed(sd_dhcp_client *client) {
         client->xid = random_u32();
 
         r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
-                                         client->mac_addr, client->mac_addr_len,
-                                         client->bcast_addr, client->bcast_addr_len,
+                                         &client->hw_addr, &client->bcast_addr,
                                          client->arp_type, client->port);
         if (r < 0) {
                 client_stop(client, r);
@@ -1481,8 +1428,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
         client->attempt = 0;
 
         r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
-                                         client->mac_addr, client->mac_addr_len,
-                                         client->bcast_addr, client->bcast_addr_len,
+                                         &client->hw_addr, &client->bcast_addr,
                                          client->arp_type, client->port);
         if (r < 0) {
                 client_stop(client, r);
@@ -1946,7 +1892,7 @@ static int client_receive_message_udp(
 
         if (client->arp_type == ARPHRD_ETHER) {
                 expected_hlen = ETH_ALEN;
-                expected_chaddr = &client->mac_addr[0];
+                expected_chaddr = client->hw_addr.bytes;
         }
 
         if (message->hlen != expected_hlen) {
@@ -2042,6 +1988,7 @@ static int client_receive_message_raw(
 
 int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
         assert_return(client, -EINVAL);
+        assert_return(sd_dhcp_client_is_running(client), -ESTALE);
         assert_return(client->fd >= 0, -EINVAL);
 
         if (!client->lease)
@@ -2089,7 +2036,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
 
 int sd_dhcp_client_send_release(sd_dhcp_client *client) {
         assert_return(client, -EINVAL);
-        assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+        assert_return(sd_dhcp_client_is_running(client), -ESTALE);
         assert_return(client->lease, -EUNATCH);
 
         _cleanup_free_ DHCPPacket *release = NULL;
@@ -2102,7 +2049,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
 
         /* Fill up release IP and MAC */
         release->dhcp.ciaddr = client->lease->address;
-        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+        memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
 
         r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
@@ -2124,7 +2071,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
 
 int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
         assert_return(client, -EINVAL);
-        assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+        assert_return(sd_dhcp_client_is_running(client), -ESTALE);
         assert_return(client->lease, -EUNATCH);
 
         _cleanup_free_ DHCPPacket *release = NULL;
@@ -2136,7 +2083,7 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
                 return r;
 
         release->dhcp.ciaddr = client->lease->address;
-        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+        memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
 
         r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
@@ -2181,6 +2128,7 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t
 
         assert_return(client, -EINVAL);
         assert_return(!client->event, -EBUSY);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         if (event)
                 client->event = sd_event_ref(event);
@@ -2197,6 +2145,7 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t
 
 int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
         assert_return(client, -EINVAL);
+        assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
 
         client->event = sd_event_unref(client->event);
 
@@ -2253,7 +2202,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
                 .state = DHCP_STATE_INIT,
                 .ifindex = -1,
                 .fd = -1,
-                .mtu = DHCP_DEFAULT_MIN_SIZE,
+                .mtu = DHCP_MIN_PACKET_SIZE,
                 .port = DHCP_PORT_CLIENT,
                 .anonymize = !!anonymize,
                 .max_attempts = UINT64_MAX,
index 388c5cd2a4b48ed10d2b6bcc6d4b32faad67eb3c..734a4fa27df088e052cdbc0d08efb78053e1de5d 100644 (file)
@@ -713,9 +713,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
                 r = lease_parse_u16(option, len, &lease->mtu, 68);
                 if (r < 0)
                         log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
-                if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
-                        log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
-                        lease->mtu = DHCP_DEFAULT_MIN_SIZE;
+                if (lease->mtu < DHCP_MIN_PACKET_SIZE) {
+                        log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_MIN_PACKET_SIZE);
+                        lease->mtu = DHCP_MIN_PACKET_SIZE;
                 }
 
                 break;
index 3de10cc19950a7844a326d83a0644323b15cb5b7..26114900677cd04f0a88ab2a8f8bed4c40d00711 100644 (file)
@@ -116,9 +116,8 @@ int sd_dhcp6_client_set_mac(
                 return 0;
         }
 
-        memcpy(client->hw_addr.bytes, addr, addr_len);
-        client->hw_addr.length = addr_len;
         client->arp_type = arp_type;
+        hw_addr_set(&client->hw_addr, addr, addr_len);
 
         return 0;
 }
@@ -216,8 +215,8 @@ static int dhcp6_client_set_duid_internal(
                 client->duid_len = sizeof(client->duid.type) + duid_len;
 
         } else {
-                r = dhcp_identifier_set_duid(duid_type, client->hw_addr.bytes, client->hw_addr.length,
-                                             client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len);
+                r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time,
+                                             client->test_mode, &client->duid, &client->duid_len);
                 if (r == -EOPNOTSUPP)
                         return log_dhcp6_client_errno(client, r,
                                                       "Failed to set %s. MAC address is not set or "
@@ -300,7 +299,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
         if (client->iaid_set)
                 return 0;
 
-        r = dhcp_identifier_set_iaid(client->ifindex, client->hw_addr.bytes, client->hw_addr.length,
+        r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
                                      /* legacy_unstable_byteorder = */ true,
                                      /* use_mac = */ client->test_mode,
                                      &iaid);
@@ -544,13 +543,9 @@ static void client_notify(sd_dhcp6_client *client, int event) {
                 client->callback(client, event, client->userdata);
 }
 
-static void client_stop(sd_dhcp6_client *client, int error) {
-        DHCP6_CLIENT_DONT_DESTROY(client);
-
+static void client_cleanup(sd_dhcp6_client *client) {
         assert(client);
 
-        client_notify(client, error);
-
         client->lease = sd_dhcp6_lease_unref(client->lease);
 
         /* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
@@ -567,6 +562,16 @@ static void client_stop(sd_dhcp6_client *client, int error) {
         client_set_state(client, DHCP6_STATE_STOPPED);
 }
 
+static void client_stop(sd_dhcp6_client *client, int error) {
+        DHCP6_CLIENT_DONT_DESTROY(client);
+
+        assert(client);
+
+        client_notify(client, error);
+
+        client_cleanup(client);
+}
+
 static int client_append_common_options_in_managed_mode(
                 sd_dhcp6_client *client,
                 uint8_t **opt,
@@ -685,6 +690,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *opt
                 req_opts = client->req_opts;
         }
 
+        if (n == 0)
+                return 0;
+
         return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
 }
 
@@ -1134,6 +1142,20 @@ static int client_process_reply(
                 return log_invalid_message_type(client, message);
 
         r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
+        if (r == -EADDRNOTAVAIL) {
+
+                /* If NoBinding status code is received, we cannot request the address anymore.
+                 * Let's restart transaction from the beginning. */
+
+                if (client->state == DHCP6_STATE_REQUEST)
+                        /* The lease is not acquired yet, hence it is not necessary to notify the restart. */
+                        client_cleanup(client);
+                else
+                        /* We need to notify the previous lease was expired. */
+                        client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
+
+                return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
+        }
         if (r < 0)
                 return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
 
index f588514cb646ba537e177ca47b6c423766e694c3..57c23965eda3ab3b73b0bfdf61856213fa879756 100644 (file)
@@ -512,7 +512,7 @@ static int dhcp6_lease_parse_message(
                                 return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
 
                         if (r > 0)
-                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
                                                               "Received %s message with non-zero status: %s%s%s",
                                                               dhcp6_message_type_to_string(message->type),
                                                               strempty(msg), isempty(msg) ? "" : ": ",
index fb86e6c994c7f666fbe1670596bb56091cbb1d9d..8344dc4f4a806505ae1cdbaa9cfe306fc9f9a471 100644 (file)
 #include "dhcp-identifier.h"
 #include "dhcp-internal.h"
 #include "dhcp-protocol.h"
+#include "ether-addr-util.h"
 #include "fd-util.h"
 #include "random-util.h"
 #include "tests.h"
 #include "util.h"
 
-static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
-static uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
+static struct hw_addr_data hw_addr = {
+        .length = ETH_ALEN,
+        .ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
+}, bcast_addr = {
+        .length = ETH_ALEN,
+        .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
+};
 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
 
 static bool verbose = true;
@@ -139,9 +144,9 @@ static void test_dhcp_identifier_set_iaid(void) {
         uint32_t iaid_legacy;
         be32_t iaid;
 
-        assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ true,
+        assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true,
                                            /* use_mac = */ true, &iaid_legacy) >= 0);
-        assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ false,
+        assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ false,
                                            /* use_mac = */ true, &iaid) >= 0);
 
         /* we expect, that the MAC address was hashed. The legacy value is in native
@@ -164,7 +169,7 @@ static int check_options(uint8_t code, uint8_t len, const void *option, void *us
                 size_t duid_len;
 
                 assert_se(dhcp_identifier_set_duid_en(/* test_mode = */ true, &duid, &duid_len) >= 0);
-                assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, true, /* use_mac = */ true, &iaid) >= 0);
+                assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true, /* use_mac = */ true, &iaid) >= 0);
 
                 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
                 assert_se(len == 19);
@@ -217,7 +222,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const
         assert_se(ip_check == 0xffff);
 
         assert_se(discover->dhcp.xid);
-        assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
+        assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
 
         size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
 
@@ -231,8 +236,8 @@ int dhcp_network_bind_raw_socket(
                 int ifindex,
                 union sockaddr_union *link,
                 uint32_t id,
-                const uint8_t *addr, size_t addr_len,
-                const uint8_t *bcaddr, size_t bcaddr_len,
+                const struct hw_addr_data *_hw_addr,
+                const struct hw_addr_data *_bcast_addr,
                 uint16_t arp_type, uint16_t port) {
 
         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
@@ -282,7 +287,7 @@ static void test_discover_message(sd_event *e) {
         assert_se(r >= 0);
 
         assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
-        assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
+        assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
         dhcp_client_set_test_mode(client, true);
 
         assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
@@ -440,7 +445,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
 
         memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
         memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
-        memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
+        memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
 
         callback_recv = NULL;
 
@@ -471,7 +476,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
 
         memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
         memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
-        memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
+        memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
 
         callback_recv = test_addr_acq_recv_request;
 
@@ -500,7 +505,7 @@ static void test_addr_acq(sd_event *e) {
         assert_se(r >= 0);
 
         assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
-        assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
+        assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
         dhcp_client_set_test_mode(client, true);
 
         assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
index 5c5446e9876fa844d4ff05002fc487b1d5e95d30..215b6cf87fefb1100b5fa177eb0ef71cf8289680 100644 (file)
@@ -785,6 +785,8 @@ global:
         sd_bus_error_setfv;
 
         sd_device_new_child;
+        sd_device_monitor_set_description;
+        sd_device_monitor_get_description;
 
         sd_id128_string_equal;
 
index 39f769c35cf65bd240363219a1f069b9916dd8fa..30f2520b7245eed5febba2f0d6bc809ae279553f 100644 (file)
@@ -157,9 +157,7 @@ _public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumer
         else
                 hashmap = &enumerator->nomatch_sysattr;
 
-        /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
-         * multiple times with the same sysattr but different value. */
-        r = hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
+        r = update_match_strv(hashmap, sysattr, value, /* clear_on_null = */ true);
         if (r <= 0)
                 return r;
 
@@ -174,9 +172,7 @@ _public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enume
         assert_return(enumerator, -EINVAL);
         assert_return(property, -EINVAL);
 
-        /* Do not use string_has_ops_free_free or hashmap_put_strdup() here, as this may be called
-         * multiple times with the same property but different value. */
-        r = hashmap_put_strdup_full(&enumerator->match_property, &trivial_hash_ops_free_free, property, value);
+        r = update_match_strv(&enumerator->match_property, property, value, /* clear_on_null = */ false);
         if (r <= 0)
                 return r;
 
@@ -466,29 +462,25 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de
 }
 
 static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
-        const char *property;
-        const char *value;
+        const char *property_pattern;
+        char * const *value_patterns;
 
         assert(enumerator);
         assert(device);
 
+        /* Unlike device_match_sysattr(), this accepts device that has at least one matching property. */
+
         if (hashmap_isempty(enumerator->match_property))
                 return true;
 
-        HASHMAP_FOREACH_KEY(value, property, enumerator->match_property) {
-                const char *property_dev, *value_dev;
+        HASHMAP_FOREACH_KEY(value_patterns, property_pattern, enumerator->match_property) {
+                const char *property, *value;
 
-                FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
-                        if (fnmatch(property, property_dev, 0) != 0)
+                FOREACH_DEVICE_PROPERTY(device, property, value) {
+                        if (fnmatch(property_pattern, property, 0) != 0)
                                 continue;
 
-                        if (!value && !value_dev)
-                                return true;
-
-                        if (!value || !value_dev)
-                                continue;
-
-                        if (fnmatch(value, value_dev, 0) == 0)
+                        if (strv_fnmatch(value_patterns, value))
                                 return true;
                 }
         }
@@ -750,8 +742,6 @@ static int enumerator_scan_dir(
         if (!dir)
                 return -errno;
 
-        log_debug("sd-device-enumerator: Scanning %s", path);
-
         FOREACH_DIRENT_ALL(de, dir, return -errno) {
                 int k;
 
@@ -957,8 +947,6 @@ static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
 static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
         int k, r = 0;
 
-        log_debug("sd-device-enumerator: Scan all dirs");
-
         k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
         if (k < 0)
                 r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
index e8913c3d1f8a3c3433d8bfdf384b78f76949f891..566280d66f3f03da729a64fa2dfaf7d2c6c4918b 100644 (file)
 #include "string-util.h"
 #include "strv.h"
 
+#define log_monitor(m, format, ...)                                     \
+        log_debug("sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_monitor_errno(m, r, format, ...)                            \
+        log_debug_errno(r, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_device_monitor(d, m, format, ...)                           \
+        log_device_debug(d, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+#define log_device_monitor_errno(d, m, r, format, ...)                  \
+        log_device_debug_errno(d, r, "sd-device-monitor(%s): " format, strna(m ? m->description : NULL), ##__VA_ARGS__)
+
 struct sd_device_monitor {
         unsigned n_ref;
 
@@ -46,6 +55,7 @@ struct sd_device_monitor {
 
         sd_event *event;
         sd_event_source *event_source;
+        char *description;
         sd_device_monitor_handler_t callback;
         void *userdata;
 };
@@ -139,14 +149,14 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
                  * will not receive any messages.
                  */
 
-                log_debug("sd-device-monitor: The udev service seems not to be active, disabling the monitor");
+                log_monitor(m, "The udev service seems not to be active, disabling the monitor.");
                 group = MONITOR_GROUP_NONE;
         }
 
         if (fd < 0) {
                 sock = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
                 if (sock < 0)
-                        return log_debug_errno(errno, "sd-device-monitor: Failed to create socket: %m");
+                        return log_monitor_errno(m, errno, "Failed to create socket: %m");
         }
 
         m = new(sd_device_monitor, 1);
@@ -164,7 +174,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
         if (fd >= 0) {
                 r = monitor_set_nl_address(m);
                 if (r < 0) {
-                        log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m");
+                        log_monitor_errno(m, r, "Failed to set netlink address: %m");
                         goto fail;
                 }
         }
@@ -179,12 +189,12 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
 
                 netns = ioctl(m->sock, SIOCGSKNS);
                 if (netns < 0)
-                        log_debug_errno(errno, "sd-device-monitor: Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns, ignoring: %m");
+                        log_monitor_errno(m, errno, "Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns, ignoring: %m");
                 else {
                         struct stat a, b;
 
                         if (fstat(netns, &a) < 0) {
-                                r = log_debug_errno(errno, "sd-device-monitor: Failed to stat netns of udev netlink socket: %m");
+                                r = log_monitor_errno(m, errno, "Failed to stat netns of udev netlink socket: %m");
                                 goto fail;
                         }
 
@@ -192,12 +202,12 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
                                 if (ERRNO_IS_PRIVILEGE(errno))
                                         /* If we can't access PID1's netns info due to permissions, it's fine, this is a
                                          * safety check only after all. */
-                                        log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns, ignoring: %m");
+                                        log_monitor_errno(m, errno, "No permission to stat PID1's netns, unable to determine if we are in host netns, ignoring: %m");
                                 else
-                                        log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m");
+                                        log_monitor_errno(m, errno, "Failed to stat PID1's netns, ignoring: %m");
 
                         } else if (!stat_inode_same(&a, &b))
-                                log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events.");
+                                log_monitor(m, "Netlink socket we listen on is not from host netns, we won't see device events.");
                 }
         }
 
@@ -263,7 +273,7 @@ _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_han
         if (r < 0)
                 return r;
 
-        (void) sd_event_source_set_description(m->event_source, "sd-device-monitor");
+        (void) sd_event_source_set_description(m->event_source, m->description ?: "sd-device-monitor");
 
         return 0;
 }
@@ -306,6 +316,29 @@ _public_ sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *
         return m->event_source;
 }
 
+_public_ int sd_device_monitor_set_description(sd_device_monitor *m, const char *description) {
+        int r;
+
+        assert_return(m, -EINVAL);
+
+        r = free_and_strdup(&m->description, description);
+        if (r <= 0)
+                return r;
+
+        if (m->event_source)
+                (void) sd_event_source_set_description(m->event_source, description);
+
+        return r;
+}
+
+_public_ int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret) {
+        assert_return(m, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        *ret = m->description;
+        return 0;
+}
+
 int device_monitor_enable_receiving(sd_device_monitor *m) {
         int r;
 
@@ -313,22 +346,22 @@ int device_monitor_enable_receiving(sd_device_monitor *m) {
 
         r = sd_device_monitor_filter_update(m);
         if (r < 0)
-                return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
+                return log_monitor_errno(m, r, "Failed to update filter: %m");
 
         if (!m->bound) {
                 /* enable receiving of sender credentials */
                 r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
                 if (r < 0)
-                        return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
+                        return log_monitor_errno(m, r, "Failed to set socket option SO_PASSCRED: %m");
 
                 if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
-                        return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket: %m");
+                        return log_monitor_errno(m, errno, "Failed to bind monitoring socket: %m");
 
                 m->bound = true;
 
                 r = monitor_set_nl_address(m);
                 if (r < 0)
-                        return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
+                        return log_monitor_errno(m, r, "Failed to set address: %m");
         }
 
         return 0;
@@ -339,6 +372,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
 
         (void) sd_device_monitor_detach_event(m);
 
+        free(m->description);
         hashmap_free(m->subsystem_filter);
         set_free(m->tag_filter);
         hashmap_free(m->match_sysattr_filter);
@@ -446,49 +480,49 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
 
         buflen = recvmsg(m->sock, &smsg, 0);
         if (buflen < 0) {
-                if (ERRNO_IS_TRANSIENT(errno))
-                        log_debug_errno(errno, "sd-device-monitor: Failed to receive message: %m");
+                if (!ERRNO_IS_TRANSIENT(errno))
+                        log_monitor_errno(m, errno, "Failed to receive message: %m");
                 return -errno;
         }
 
         if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
-                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "sd-device-monitor: Invalid message length.");
+                return log_monitor_errno(m, SYNTHETIC_ERRNO(EINVAL), "Invalid message length.");
 
         if (snl.nl.nl_groups == MONITOR_GROUP_NONE) {
                 /* unicast message, check if we trust the sender */
                 if (m->snl_trusted_sender.nl.nl_pid == 0 ||
                     snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Unicast netlink message ignored.");
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Unicast netlink message ignored.");
 
         } else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) {
                 if (snl.nl.nl_pid > 0)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Multicast kernel netlink message from PID %"PRIu32" ignored.",
+                                                 snl.nl.nl_pid);
         }
 
         cmsg = CMSG_FIRSTHDR(&smsg);
         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
-                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                       "sd-device-monitor: No sender credentials received, message ignored.");
+                return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                         "No sender credentials received, ignoring message.");
 
         cred = (struct ucred*) CMSG_DATA(cmsg);
         if (cred->uid != 0)
-                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                       "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid);
+                return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                         "Sender uid="UID_FMT", message ignored.", cred->uid);
 
         if (streq(buf.raw, "libudev")) {
                 /* udev message needs proper version magic */
                 if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Invalid message signature (%x != %x)",
-                                               buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Invalid message signature (%x != %x).",
+                                                 buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
 
                 if (buf.nlh.properties_off+32 > (size_t) buflen)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Invalid message length (%u > %zd)",
-                                               buf.nlh.properties_off+32, buflen);
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Invalid message length (%u > %zd).",
+                                                 buf.nlh.properties_off+32, buflen);
 
                 bufpos = buf.nlh.properties_off;
 
@@ -499,18 +533,18 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
                 /* kernel message with header */
                 bufpos = strlen(buf.raw) + 1;
                 if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Invalid message length");
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Invalid message length.");
 
                 /* check message header */
                 if (!strstr(buf.raw, "@/"))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
-                                               "sd-device-monitor: Invalid message header");
+                        return log_monitor_errno(m, SYNTHETIC_ERRNO(EAGAIN),
+                                                 "Invalid message header.");
         }
 
         r = device_new_from_nulstr(&device, &buf.raw[bufpos], buflen - bufpos);
         if (r < 0)
-                return log_debug_errno(r, "sd-device-monitor: Failed to create device from received message: %m");
+                return log_monitor_errno(m, r, "Failed to create device from received message: %m");
 
         if (is_initialized)
                 device_set_is_initialized(device);
@@ -518,9 +552,9 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
         /* Skip device, if it does not pass the current filter */
         r = passes_filter(m, device);
         if (r < 0)
-                return log_device_debug_errno(device, r, "sd-device-monitor: Failed to check received device passing filter: %m");
+                return log_device_monitor_errno(device, m, r, "Failed to check received device passing filter: %m");
         if (r == 0)
-                log_device_debug(device, "sd-device-monitor: Received device does not pass filter, ignoring");
+                log_device_monitor(device, m, "Received device does not pass filter, ignoring.");
         else
                 *ret = TAKE_PTR(device);
 
@@ -576,15 +610,15 @@ int device_monitor_send_device(
 
         r = device_get_properties_nulstr(device, &buf, &blen);
         if (r < 0)
-                return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m");
+                return log_device_monitor_errno(device, m, r, "Failed to get device properties: %m");
         if (blen < 32)
-                log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
-                                       "sd-device-monitor: Length of device property nulstr is too small to contain valid device information");
+                return log_device_monitor_errno(device, m, SYNTHETIC_ERRNO(EINVAL),
+                                                "Length of device property nulstr is too small to contain valid device information.");
 
         /* fill in versioned header */
         r = sd_device_get_subsystem(device, &val);
         if (r < 0)
-                return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device subsystem: %m");
+                return log_device_monitor_errno(device, m, r, "Failed to get device subsystem: %m");
         nlh.filter_subsystem_hash = htobe32(string_hash32(val));
 
         if (sd_device_get_devtype(device, &val) >= 0)
@@ -616,13 +650,13 @@ int device_monitor_send_device(
         count = sendmsg(m->sock, &smsg, 0);
         if (count < 0) {
                 if (!destination && errno == ECONNREFUSED) {
-                        log_device_debug(device, "sd-device-monitor: Passed to netlink monitor");
+                        log_device_monitor(device, m, "Passed to netlink monitor.");
                         return 0;
                 } else
-                        return log_device_debug_errno(device, errno, "sd-device-monitor: Failed to send device to netlink monitor: %m");
+                        return log_device_monitor_errno(device, m, errno, "Failed to send device to netlink monitor: %m");
         }
 
-        log_device_debug(device, "sd-device-monitor: Passed %zi byte to netlink monitor", count);
+        log_device_monitor(device, m, "Passed %zi byte to netlink monitor.", count);
         return count;
 }
 
@@ -787,7 +821,7 @@ _public_ int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, co
                 hashmap = &m->nomatch_sysattr_filter;
 
         /* TODO: unset m->filter_uptodate on success when we support this filter on BPF. */
-        return hashmap_put_strdup_full(hashmap, &trivial_hash_ops_free_free, sysattr, value);
+        return update_match_strv(hashmap, sysattr, value, /* clear_on_null = */ true);
 }
 
 _public_ int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match) {
index 616c16c1fc4f47e87aada43e151200b28639ed4c..3b8689e0d656225679948bd72785e29ebb38bfcc 100644 (file)
@@ -5,7 +5,65 @@
 #include "device-util.h"
 #include "path-util.h"
 
-static bool device_match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
+int update_match_strv(Hashmap **match_strv, const char *key, const char *value, bool clear_on_null) {
+        char **strv;
+        int r;
+
+        assert(match_strv);
+        assert(key);
+
+        strv = hashmap_get(*match_strv, key);
+        if (strv) {
+                if (!value) {
+                        char **v;
+
+                        if (strv_isempty(strv) || !clear_on_null)
+                                return 0;
+
+                        /* Accept all value. Clear previous assignment. */
+
+                        v = new0(char*, 1);
+                        if (!v)
+                                return -ENOMEM;
+
+                        strv_free_and_replace(strv, v);
+                } else {
+                        if (strv_contains(strv, value))
+                                return 0;
+
+                        r = strv_extend(&strv, value);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = hashmap_update(*match_strv, key, strv);
+                if (r < 0)
+                        return r;
+
+        } else {
+                _cleanup_strv_free_ char **strv_alloc = NULL;
+                _cleanup_free_ char *key_alloc = NULL;
+
+                key_alloc = strdup(key);
+                if (!key_alloc)
+                        return -ENOMEM;
+
+                strv_alloc = strv_new(value);
+                if (!strv_alloc)
+                        return -ENOMEM;
+
+                r = hashmap_ensure_put(match_strv, &string_hash_ops_free_strv_free, key_alloc, strv_alloc);
+                if (r < 0)
+                        return r;
+
+                TAKE_PTR(key_alloc);
+                TAKE_PTR(strv_alloc);
+        }
+
+        return 1;
+}
+
+static bool device_match_sysattr_value(sd_device *device, const char *sysattr, char * const *patterns) {
         const char *value;
 
         assert(device);
@@ -14,27 +72,21 @@ static bool device_match_sysattr_value(sd_device *device, const char *sysattr, c
         if (sd_device_get_sysattr_value(device, sysattr, &value) < 0)
                 return false;
 
-        if (!match_value)
-                return true;
-
-        if (fnmatch(match_value, value, 0) == 0)
-                return true;
-
-        return false;
+        return strv_fnmatch_or_empty(patterns, value, 0);
 }
 
 bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr) {
+        char * const *patterns;
         const char *sysattr;
-        const char *value;
 
         assert(device);
 
-        HASHMAP_FOREACH_KEY(value, sysattr, match_sysattr)
-                if (!device_match_sysattr_value(device, sysattr, value))
+        HASHMAP_FOREACH_KEY(patterns, sysattr, match_sysattr)
+                if (!device_match_sysattr_value(device, sysattr, patterns))
                         return false;
 
-        HASHMAP_FOREACH_KEY(value, sysattr, nomatch_sysattr)
-                if (device_match_sysattr_value(device, sysattr, value))
+        HASHMAP_FOREACH_KEY(patterns, sysattr, nomatch_sysattr)
+                if (device_match_sysattr_value(device, sysattr, patterns))
                         return false;
 
         return true;
index 4eda2abaf366c7b67144393b16680188db22a0e1..d9e9f1e8c4a0a8581b8144ed08a2e97d8522f52f 100644 (file)
@@ -82,5 +82,6 @@
 #define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
 #define log_device_error_errno(device, error, ...)   log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
 
+int update_match_strv(Hashmap **match_strv, const char *key, const char *value, bool clear_on_null);
 bool device_match_sysattr(sd_device *device, Hashmap *match_sysattr, Hashmap *nomatch_sysattr);
 bool device_match_parent(sd_device *device, Set *match_parent, Set *nomatch_parent);
index 1050234afe980c21d8702696eac218615c498804..8574337bda9670a04fa7bcd7ea1ba47ce1a8c7b0 100644 (file)
@@ -145,15 +145,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
         assert(device);
         assert(_syspath);
 
-        /* must be a subdirectory of /sys */
-        if (!path_startswith(_syspath, "/sys/"))
-                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "sd-device: Syspath '%s' is not a subdirectory of /sys",
-                                       _syspath);
-
         if (verify) {
                 _cleanup_close_ int fd = -1;
 
+                /* The input path maybe a symlink located outside of /sys. Let's try to chase the symlink at first.
+                 * The primary usecase is that e.g. /proc/device-tree is a symlink to /sys/firmware/devicetree/base.
+                 * By chasing symlinks in the path at first, we can call sd_device_new_from_path() with such path. */
                 r = chase_symlinks(_syspath, NULL, 0, &syspath, &fd);
                 if (r == -ENOENT)
                          /* the device does not exist (any more?) */
@@ -230,6 +227,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
                                                        "sd-device: the syspath \"%s\" is outside of sysfs, refusing.", syspath);
                 }
         } else {
+                /* must be a subdirectory of /sys */
+                if (!path_startswith(_syspath, "/sys/"))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "sd-device: Syspath '%s' is not a subdirectory of /sys",
+                                               _syspath);
+
                 syspath = strdup(_syspath);
                 if (!syspath)
                         return log_oom_debug();
@@ -250,13 +253,16 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
         return 0;
 }
 
-_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
+static int device_new_from_syspath(sd_device **ret, const char *syspath, bool strict) {
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         int r;
 
         assert_return(ret, -EINVAL);
         assert_return(syspath, -EINVAL);
 
+        if (strict && !path_startswith(syspath, "/sys/"))
+                return -EINVAL;
+
         r = device_new_aux(&device);
         if (r < 0)
                 return r;
@@ -269,6 +275,10 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
         return 0;
 }
 
+_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
+        return device_new_from_syspath(ret, syspath, /* strict = */ true);
+}
+
 static int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) {
         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
         _cleanup_free_ char *syspath = NULL;
@@ -516,7 +526,7 @@ _public_ int sd_device_new_from_path(sd_device **ret, const char *path) {
         if (path_startswith(path, "/dev"))
                 return sd_device_new_from_devname(ret, path);
 
-        return sd_device_new_from_syspath(ret, path);
+        return device_new_from_syspath(ret, path, /* strict = */ false);
 }
 
 int device_set_devtype(sd_device *device, const char *devtype) {
index 67f9bf4ae11283b795e04b2138522751c741d729..66ca63600d7b3ebd834118824af8312bfaba8dc9 100644 (file)
@@ -10,6 +10,7 @@
 #include "device-private.h"
 #include "device-util.h"
 #include "macro.h"
+#include "path-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "tests.h"
@@ -39,13 +40,13 @@ static void test_receive_device_fail(void) {
         assert_se(sd_device_get_syspath(loopback, &syspath) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(device_monitor_send_device(monitor_server, monitor_client, loopback) >= 0);
         assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
@@ -61,13 +62,13 @@ static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         if (subsystem_filter) {
                 assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
@@ -98,14 +99,14 @@ static void test_subsystem_filter(sd_device *device) {
         assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
         assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(sd_device_enumerator_new(&e) >= 0);
         assert_se(sd_device_enumerator_add_match_subsystem(e, subsystem, false) >= 0);
@@ -115,6 +116,9 @@ static void test_subsystem_filter(sd_device *device) {
                 assert_se(sd_device_get_syspath(d, &p) >= 0);
                 assert_se(sd_device_get_subsystem(d, &s) >= 0);
 
+                assert_se(device_add_property(d, "ACTION", "add") >= 0);
+                assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
                 log_device_debug(d, "Sending device subsystem:%s syspath:%s", s, p);
                 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
         }
@@ -135,14 +139,14 @@ static void test_tag_filter(sd_device *device) {
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
         assert_se(sd_device_monitor_filter_add_match_tag(monitor_client, "TEST_SD_DEVICE_MONITOR") >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(sd_device_enumerator_new(&e) >= 0);
         FOREACH_DEVICE(e, d) {
@@ -150,6 +154,9 @@ static void test_tag_filter(sd_device *device) {
 
                 assert_se(sd_device_get_syspath(d, &p) >= 0);
 
+                assert_se(device_add_property(d, "ACTION", "add") >= 0);
+                assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
                 log_device_debug(d, "Sending device syspath:%s", p);
                 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
         }
@@ -163,27 +170,23 @@ static void test_tag_filter(sd_device *device) {
 static void test_sysattr_filter(sd_device *device, const char *sysattr) {
         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        const char *syspath, *subsystem, *sysattr_value;
+        const char *syspath, *sysattr_value;
         sd_device *d;
 
         log_device_info(device, "/* %s(%s) */", __func__, sysattr);
 
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
-        assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
         assert_se(sd_device_get_sysattr_value(device, sysattr, &sysattr_value) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
-        /* The sysattr filter is not implemented in BPF yet, so the below device_monito_send_device()
-         * may cause EAGAIN. So, let's also filter devices with subsystem. */
-        assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
         assert_se(sd_device_monitor_filter_add_match_sysattr(monitor_client, sysattr, sysattr_value, true) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(sd_device_enumerator_new(&e) >= 0);
         assert_se(sd_device_enumerator_add_match_sysattr(e, sysattr, sysattr_value, false) >= 0);
@@ -192,8 +195,16 @@ static void test_sysattr_filter(sd_device *device, const char *sysattr) {
 
                 assert_se(sd_device_get_syspath(d, &p) >= 0);
 
+                assert_se(device_add_property(d, "ACTION", "add") >= 0);
+                assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
+
                 log_device_debug(d, "Sending device syspath:%s", p);
                 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+
+                /* The sysattr filter is not implemented in BPF yet. So, sending multiple devices may fills up
+                 * buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
+                 * which should be filtered out by the receiver. */
+                break;
         }
 
         log_device_info(device, "Sending device syspath:%s", syspath);
@@ -205,39 +216,46 @@ static void test_sysattr_filter(sd_device *device, const char *sysattr) {
 static void test_parent_filter(sd_device *device) {
         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        const char *syspath, *subsystem;
+        const char *syspath, *parent_syspath;
         sd_device *parent, *d;
         int r;
 
         log_device_info(device, "/* %s */", __func__);
 
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
-        assert_se(sd_device_get_subsystem(device, &subsystem) >= 0);
         r = sd_device_get_parent(device, &parent);
         if (r < 0)
                 return (void) log_device_info(device, "Device does not have parent, skipping.");
+        assert_se(sd_device_get_syspath(parent, &parent_syspath) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
-        /* The parent filter is not implemented in BPF yet, so the below device_monito_send_device()
-         * may cause EAGAIN. So, let's also filter devices with subsystem. */
-        assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, subsystem, NULL) >= 0);
         assert_se(sd_device_monitor_filter_add_match_parent(monitor_client, parent, true) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(sd_device_enumerator_new(&e) >= 0);
         FOREACH_DEVICE(e, d) {
                 const char *p;
 
                 assert_se(sd_device_get_syspath(d, &p) >= 0);
+                if (path_startswith(p, parent_syspath))
+                        continue;
+
+                assert_se(device_add_property(d, "ACTION", "add") >= 0);
+                assert_se(device_add_property(d, "SEQNUM", "10") >= 0);
 
                 log_device_debug(d, "Sending device syspath:%s", p);
                 assert_se(device_monitor_send_device(monitor_server, monitor_client, d) >= 0);
+
+                /* The parent filter is not implemented in BPF yet. So, sending multiple devices may fills up
+                 * buffer and device_monitor_send_device() may return EAGAIN. Let's send one device here,
+                 * which should be filtered out by the receiver. */
+                break;
         }
 
         log_device_info(device, "Sending device syspath:%s", syspath);
@@ -255,13 +273,13 @@ static void test_sd_device_monitor_filter_remove(sd_device *device) {
         assert_se(sd_device_get_syspath(device, &syspath) >= 0);
 
         assert_se(device_monitor_new_full(&monitor_server, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_server, "sender") >= 0);
         assert_se(sd_device_monitor_start(monitor_server, NULL, NULL) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_server), "sender") >= 0);
 
         assert_se(device_monitor_new_full(&monitor_client, MONITOR_GROUP_NONE, -1) >= 0);
+        assert_se(sd_device_monitor_set_description(monitor_client, "receiver") >= 0);
         assert_se(device_monitor_allow_unicast_sender(monitor_client, monitor_server) >= 0);
         assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
-        assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
 
         assert_se(sd_device_monitor_filter_add_match_subsystem_devtype(monitor_client, "hoge", NULL) >= 0);
         assert_se(sd_device_monitor_filter_update(monitor_client) >= 0);
index 91e358e4645240f888e3c0c3b306072d524e922f..8172c64e456d31d60dc40b583b2099048c54d9e4 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <ctype.h>
 #include <fcntl.h>
+#include <unistd.h>
 
 #include "device-enumerator-private.h"
 #include "device-internal.h"
 #include "hashmap.h"
 #include "nulstr-util.h"
 #include "path-util.h"
+#include "rm-rf.h"
 #include "string-util.h"
 #include "tests.h"
 #include "time-util.h"
+#include "tmpfile-util.h"
 
 static void test_sd_device_one(sd_device *d) {
         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
@@ -310,6 +313,49 @@ TEST(sd_device_enumerator_filter_subsystem) {
         assert_se(n_new_dev + n_removed_dev <= 10);
 }
 
+TEST(sd_device_enumerator_add_match_sysattr) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int ifindex;
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+        assert_se(sd_device_enumerator_add_match_subsystem(e, "net", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "hoge", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "foo", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "bar", false) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "baz", false) >= 0);
+
+        dev = sd_device_enumerator_get_device_first(e);
+        assert_se(dev);
+        assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
+        assert_se(ifindex == 1);
+
+        assert_se(!sd_device_enumerator_get_device_next(e));
+}
+
+TEST(sd_device_enumerator_add_match_property) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int ifindex;
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+        assert_se(sd_device_enumerator_add_match_subsystem(e, "net", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true) >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", "1*") >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", "hoge") >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "IFINDE*", NULL) >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "AAAAA", "BBBB") >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "FOOOO", NULL) >= 0);
+
+        dev = sd_device_enumerator_get_device_first(e);
+        assert_se(dev);
+        assert_se(sd_device_get_ifindex(dev, &ifindex) >= 0);
+        assert_se(ifindex == 1);
+}
+
 TEST(sd_device_new_from_nulstr) {
         const char *devlinks =
                 "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
@@ -363,4 +409,50 @@ TEST(sd_device_new_from_nulstr) {
         }
 }
 
+TEST(sd_device_new_from_path) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
+        sd_device *dev;
+        int r;
+
+        assert_se(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir) >= 0);
+
+        assert_se(sd_device_enumerator_new(&e) >= 0);
+        assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0);
+        assert_se(sd_device_enumerator_add_match_subsystem(e, "block", true) >= 0);
+        assert_se(sd_device_enumerator_add_nomatch_sysname(e, "loop*") >= 0);
+        assert_se(sd_device_enumerator_add_match_property(e, "DEVNAME", "*") >= 0);
+
+        FOREACH_DEVICE(e, dev) {
+                _cleanup_(sd_device_unrefp) sd_device *d = NULL;
+                const char *syspath, *devpath, *sysname, *s;
+                _cleanup_free_ char *path = NULL;
+
+                assert_se(sd_device_get_sysname(dev, &sysname) >= 0);
+
+                log_debug("%s(%s)", __func__, sysname);
+
+                assert_se(sd_device_get_syspath(dev, &syspath) >= 0);
+                assert_se(sd_device_new_from_path(&d, syspath) >= 0);
+                assert_se(sd_device_get_syspath(d, &s) >= 0);
+                assert_se(streq(s, syspath));
+                d = sd_device_unref(d);
+
+                assert_se(sd_device_get_devname(dev, &devpath) >= 0);
+                r = sd_device_new_from_path(&d, devpath);
+                if (r >= 0) {
+                        assert_se(sd_device_get_syspath(d, &s) >= 0);
+                        assert_se(streq(s, syspath));
+                        d = sd_device_unref(d);
+                } else
+                        assert_se(r == -ENODEV || ERRNO_IS_PRIVILEGE(r));
+
+                assert_se(path = path_join(tmpdir, sysname));
+                assert_se(symlink(syspath, path) >= 0);
+                assert_se(sd_device_new_from_path(&d, path) >= 0);
+                assert_se(sd_device_get_syspath(d, &s) >= 0);
+                assert_se(streq(s, syspath));
+        }
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);
index a426842bbb3aa9faf8456465d958626662af72e0..65c001215d2f6439e020c98f13db9579a98c391a 100644 (file)
@@ -2361,7 +2361,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
                 log_struct(LOG_INFO,
                            LOG_MESSAGE("System shutdown has been cancelled"),
                            "ACTION=%s", handle_action_to_string(a->handle),
-                           "MESSAGE_ID=" SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED_STR,
+                           "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_CANCELED_STR,
                            username ? "OPERATOR=%s" : NULL, username);
 
                 utmp_wall("System shutdown has been cancelled",
index 003dbc0a959076d2f5c97be0e84047c827c8832c..dc6a0d5407567248acb08e36841d27f369e73820 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "alloc-util.h"
 #include "bus-util.h"
+#include "daemon-util.h"
 #include "fd-util.h"
 #include "logind-session-dbus.h"
 #include "logind-session-device.h"
@@ -376,19 +377,11 @@ error:
 }
 
 void session_device_free(SessionDevice *sd) {
-        int r;
-
         assert(sd);
 
         /* Make sure to remove the pushed fd. */
-        if (sd->pushed_fd) {
-                r = sd_notifyf(false,
-                               "FDSTOREREMOVE=1\n"
-                               "FDNAME=session-%s-device-%u-%u",
-                               sd->session->id, major(sd->dev), minor(sd->dev));
-                if (r < 0)
-                        log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
-        }
+        if (sd->pushed_fd)
+                (void) notify_remove_fd_warnf("session-%s-device-%u-%u", sd->session->id, major(sd->dev), minor(sd->dev));
 
         session_device_stop(sd);
         session_device_notify(sd, SESSION_DEVICE_RELEASE);
@@ -469,7 +462,6 @@ unsigned session_device_try_pause_all(Session *s) {
 }
 
 int session_device_save(SessionDevice *sd) {
-        _cleanup_free_ char *m = NULL;
         const char *id;
         int r;
 
@@ -489,13 +481,7 @@ int session_device_save(SessionDevice *sd) {
         id = sd->session->id;
         assert(*(id + strcspn(id, "-\n")) == '\0');
 
-        r = asprintf(&m, "FDSTORE=1\n"
-                         "FDNAME=session-%s-device-%u-%u\n",
-                         id, major(sd->dev), minor(sd->dev));
-        if (r < 0)
-                return r;
-
-        r = sd_pid_notify_with_fds(0, false, m, &sd->fd, 1);
+        r = notify_push_fdf(sd->fd, "session-%s-device-%u-%u", id, major(sd->dev), minor(sd->dev));
         if (r < 0)
                 return r;
 
index 06b1bcf9b46944ac359c507a9f56be0e90d35ba9..3f1503ad4842fdf6db35fb98e982f96edd1128fc 100644 (file)
@@ -90,7 +90,7 @@ static int warn_wall(Manager *m, usec_t n) {
         log_struct(level,
                    LOG_MESSAGE("%s", l),
                    "ACTION=%s", handle_action_to_string(m->scheduled_shutdown_action->handle),
-                   "MESSAGE_ID=" SD_MESSAGE_LOGIND_SHUTDOWN_STR,
+                   "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_SCHEDULED_STR,
                    username ? "OPERATOR=%s" : NULL, username);
 
         if (m->enable_wall_messages)
index d14a17274bb0796700b41cf91905806d343324ad..3a6a6e07488412e5411f3c4c591308d98600a7c1 100644 (file)
@@ -438,7 +438,7 @@ static int deliver_fd(Manager *m, const char *fdname, int fd) {
 
 static int manager_attach_fds(Manager *m) {
         _cleanup_strv_free_ char **fdnames = NULL;
-        int r, n;
+        int n;
 
         /* Upon restart, PID1 will send us back all fds of session devices that we previously opened. Each
          * file descriptor is associated with a given session. The session ids are passed through FDNAMES. */
@@ -455,15 +455,9 @@ static int manager_attach_fds(Manager *m) {
                 if (deliver_fd(m, fdnames[i], fd) >= 0)
                         continue;
 
-                /* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd */
-                safe_close(fd);
-
-                /* Remove from fdstore as well */
-                r = sd_notifyf(false,
-                               "FDSTOREREMOVE=1\n"
-                               "FDNAME=%s", fdnames[i]);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
+                /* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd
+                 * and remove it from fdstore. */
+                close_and_notify_warn(fd, fdnames[i]);
         }
 
         return 0;
index cb6a6fb51463f13c3dd4bdb988810ac8cebba28c..98736856ee850149abe6b0364ebb2947490a7eaa 100644 (file)
@@ -411,16 +411,18 @@ static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, con
 static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
         uint64_t val;
         int r;
+        bool is_cpu_weight;
 
+        is_cpu_weight = streq(field, "CPUWeight");
         if (isempty(limit))
                 return PAM_SUCCESS;
 
-        r = cg_weight_parse(limit, &val);
+        r = is_cpu_weight ? cg_cpu_weight_parse(limit, &val) : cg_weight_parse(limit, &val);
         if (r >= 0) {
                 r = sd_bus_message_append(m, "(sv)", field, "t", val);
                 if (r < 0)
                         return pam_bus_log_create_error(handle, r);
-        } else if (streq(field, "CPUWeight"))
+        } else if (is_cpu_weight)
                 pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit);
         else
                 pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit);
index 162664ecf131afae5c85d4a19c9b6811b0d005e5..3cfcd51e63699b1c600a86b1bae6d1e89b9856ad 100644 (file)
@@ -185,12 +185,14 @@ Tun.PacketInfo,                           config_parse_bool,
 Tun.VNetHeader,                           config_parse_bool,                         0,                             offsetof(TunTap, vnet_hdr)
 Tun.User,                                 config_parse_string,                       CONFIG_PARSE_STRING_SAFE,      offsetof(TunTap, user_name)
 Tun.Group,                                config_parse_string,                       CONFIG_PARSE_STRING_SAFE,      offsetof(TunTap, group_name)
+Tun.KeepCarrier,                          config_parse_bool,                         0,                             offsetof(TunTap, keep_fd)
 Tap.OneQueue,                             config_parse_warn_compat,                  DISABLED_LEGACY,               0
 Tap.MultiQueue,                           config_parse_bool,                         0,                             offsetof(TunTap, multi_queue)
 Tap.PacketInfo,                           config_parse_bool,                         0,                             offsetof(TunTap, packet_info)
 Tap.VNetHeader,                           config_parse_bool,                         0,                             offsetof(TunTap, vnet_hdr)
 Tap.User,                                 config_parse_string,                       CONFIG_PARSE_STRING_SAFE,      offsetof(TunTap, user_name)
 Tap.Group,                                config_parse_string,                       CONFIG_PARSE_STRING_SAFE,      offsetof(TunTap, group_name)
+Tap.KeepCarrier,                          config_parse_bool,                         0,                             offsetof(TunTap, keep_fd)
 Bond.Mode,                                config_parse_bond_mode,                    0,                             offsetof(Bond, mode)
 Bond.TransmitHashPolicy,                  config_parse_bond_xmit_hash_policy,        0,                             offsetof(Bond, xmit_hash_policy)
 Bond.LACPTransmitRate,                    config_parse_bond_lacp_rate,               0,                             offsetof(Bond, lacp_rate)
index e9fadfddde8e8fa81e020c9a6dc0f23fe2434bf4..212df3daa02871e53942f0c4a08dad819f10d886 100644 (file)
@@ -237,6 +237,9 @@ void netdev_drop(NetDev *netdev) {
                 return;
         }
 
+        if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
+                NETDEV_VTABLE(netdev)->drop(netdev);
+
         netdev->state = NETDEV_STATE_LINGER;
 
         log_netdev_debug(netdev, "netdev removed");
@@ -789,6 +792,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
                         config_item_perf_lookup, network_netdev_gperf_lookup,
                         CONFIG_PARSE_WARN,
                         netdev_raw,
+                        NULL,
                         NULL);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
@@ -823,7 +827,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
                         NETDEV_VTABLE(netdev)->sections,
                         config_item_perf_lookup, network_netdev_gperf_lookup,
                         CONFIG_PARSE_WARN,
-                        netdev, NULL);
+                        netdev, NULL, NULL);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
 
index 1c7dc0f7e55d452c2426140ca73b710216a27f34..49eadbb7a442e1c02ff1388d9fd1982abf65ab51 100644 (file)
@@ -142,6 +142,9 @@ typedef struct NetDevVTable {
          * to be set != 0. */
         void (*init)(NetDev *n);
 
+        /* This is called when the interface is removed. */
+        void (*drop)(NetDev *n);
+
         /* This should free all kind-specific variables. It should be
          * idempotent. */
         void (*done)(NetDev *n);
index 6f099a144814e1f060b3e0423802bb85ed0245df..39ea7c1d739e6c1579134caf9980d4cc2b9d9cf1 100644 (file)
 #include <linux/if_tun.h>
 
 #include "alloc-util.h"
+#include "daemon-util.h"
 #include "fd-util.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "socket-util.h"
 #include "tuntap.h"
 #include "user-util.h"
 
 #define TUN_DEV "/dev/net/tun"
 
-static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
-        TunTap *t;
-
+static TunTap* TUNTAP(NetDev *netdev) {
         assert(netdev);
-        assert(netdev->ifname);
-        assert(ifr);
-
-        if (netdev->kind == NETDEV_KIND_TAP) {
-                t = TAP(netdev);
-                ifr->ifr_flags |= IFF_TAP;
-        } else {
-                t = TUN(netdev);
-                ifr->ifr_flags |= IFF_TUN;
+
+        switch (netdev->kind) {
+        case NETDEV_KIND_TAP:
+                return TAP(netdev);
+        case NETDEV_KIND_TUN:
+                return TUN(netdev);
+        default:
+                return NULL;
         }
+}
 
-        if (!t->packet_info)
-                ifr->ifr_flags |= IFF_NO_PI;
+static void *close_fd_ptr(void *p) {
+        safe_close(PTR_TO_FD(p));
+        return NULL;
+}
 
-        if (t->multi_queue)
-                ifr->ifr_flags |= IFF_MULTI_QUEUE;
+DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
 
-        if (t->vnet_hdr)
-                ifr->ifr_flags |= IFF_VNET_HDR;
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
+        _cleanup_free_ char *tuntap_name = NULL;
+        const char *p;
+        int r;
+
+        assert(m);
+        assert(fd >= 0);
+        assert(name);
+
+        p = startswith(name, "tuntap-");
+        if (!p)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unknown fd (%s).", name);
+
+        if (!ifname_valid(p))
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received tuntap fd with invalid name (%s).", p);
 
-        strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
+        tuntap_name = strdup(p);
+        if (!tuntap_name)
+                return log_oom_debug();
 
+        r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
+        if (r < 0)
+                return log_debug_errno(r, "Failed to store tuntap fd: %m");
+
+        TAKE_PTR(tuntap_name);
         return 0;
 }
 
-static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
+void manager_clear_unmanaged_tuntap_fds(Manager *m) {
+        char *name;
+        void *p;
+
+        assert(m);
+
+        while ((p = hashmap_steal_first_key_and_value(m->tuntap_fds_by_name, (void**) &name))) {
+                close_and_notify_warn(PTR_TO_FD(p), name);
+                name = mfree(name);
+        }
+}
+
+static int tuntap_take_fd(NetDev *netdev) {
+        _cleanup_free_ char *name = NULL;
+        void *p;
+        int r;
+
+        assert(netdev);
+        assert(netdev->manager);
+
+        r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
+        if (r < 0)
+                return r;
+
+        p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
+        if (!p)
+                return -ENOENT;
+
+        log_netdev_debug(netdev, "Found file descriptor in fd store.");
+        return PTR_TO_FD(p);
+}
+
+static int netdev_create_tuntap(NetDev *netdev) {
         _cleanup_close_ int fd = -1;
-        TunTap *t = NULL;
-        const char *user;
-        const char *group;
-        uid_t uid;
-        gid_t gid;
+        struct ifreq ifr = {};
+        TunTap *t;
         int r;
 
         assert(netdev);
-        assert(ifr);
+        t = TUNTAP(netdev);
+        assert(t);
 
-        fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
+        fd = TAKE_FD(t->fd);
         if (fd < 0)
-                return log_netdev_error_errno(netdev, errno,  "Failed to open tun dev: %m");
-
-        if (ioctl(fd, TUNSETIFF, ifr) < 0)
-                return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed on tun dev: %m");
+                fd = tuntap_take_fd(netdev);
+        if (fd < 0)
+                fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
+        if (fd < 0)
+                return log_netdev_error_errno(netdev, errno,  "Failed to open " TUN_DEV ": %m");
 
         if (netdev->kind == NETDEV_KIND_TAP)
-                t = TAP(netdev);
+                ifr.ifr_flags |= IFF_TAP;
         else
-                t = TUN(netdev);
+                ifr.ifr_flags |= IFF_TUN;
 
-        assert(t);
+        if (!t->packet_info)
+                ifr.ifr_flags |= IFF_NO_PI;
+
+        if (t->multi_queue)
+                ifr.ifr_flags |= IFF_MULTI_QUEUE;
+
+        if (t->vnet_hdr)
+                ifr.ifr_flags |= IFF_VNET_HDR;
+
+        strncpy(ifr.ifr_name, netdev->ifname, IFNAMSIZ-1);
+
+        if (ioctl(fd, TUNSETIFF, &ifr) < 0)
+                return log_netdev_error_errno(netdev, errno, "TUNSETIFF failed: %m");
 
         if (t->user_name) {
-                user = t->user_name;
+                const char *user = t->user_name;
+                uid_t uid;
 
                 r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
 
                 if (ioctl(fd, TUNSETOWNER, uid) < 0)
-                        return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed on tun dev: %m");
+                        return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed: %m");
         }
 
         if (t->group_name) {
-                group = t->group_name;
+                const char *group = t->group_name;
+                gid_t gid;
 
                 r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
 
                 if (ioctl(fd, TUNSETGROUP, gid) < 0)
-                        return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed on tun dev: %m");
+                        return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed: %m");
 
         }
 
         if (ioctl(fd, TUNSETPERSIST, 1) < 0)
-                return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed on tun dev: %m");
+                return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
+
+        if (t->keep_fd) {
+                t->fd = TAKE_FD(fd);
+                (void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
+        }
 
         return 0;
 }
 
-static int netdev_create_tuntap(NetDev *netdev) {
-        struct ifreq ifr = {};
-        int r;
+static void tuntap_init(NetDev *netdev) {
+        TunTap *t;
 
-        r = netdev_fill_tuntap_message(netdev, &ifr);
-        if (r < 0)
-                return r;
+        assert(netdev);
+        t = TUNTAP(netdev);
+        assert(t);
 
-        return netdev_tuntap_add(netdev, &ifr);
+        t->fd = -1;
 }
 
-static void tuntap_done(NetDev *netdev) {
-        TunTap *t = NULL;
+static void tuntap_drop(NetDev *netdev) {
+        TunTap *t;
 
         assert(netdev);
+        t = TUNTAP(netdev);
+        assert(t);
 
-        if (netdev->kind == NETDEV_KIND_TUN)
-                t = TUN(netdev);
-        else
-                t = TAP(netdev);
+        t->fd = close_and_notify_warn(t->fd, netdev->ifname);
+}
 
+static void tuntap_done(NetDev *netdev) {
+        TunTap *t;
+
+        assert(netdev);
+        t = TUNTAP(netdev);
         assert(t);
 
+        t->fd = safe_close(t->fd);
         t->user_name = mfree(t->user_name);
         t->group_name = mfree(t->group_name);
 }
@@ -149,6 +227,8 @@ const NetDevVTable tun_vtable = {
         .object_size = sizeof(TunTap),
         .sections = NETDEV_COMMON_SECTIONS "Tun\0",
         .config_verify = tuntap_verify,
+        .init = tuntap_init,
+        .drop = tuntap_drop,
         .done = tuntap_done,
         .create = netdev_create_tuntap,
         .create_type = NETDEV_CREATE_INDEPENDENT,
@@ -159,6 +239,8 @@ const NetDevVTable tap_vtable = {
         .object_size = sizeof(TunTap),
         .sections = NETDEV_COMMON_SECTIONS "Tap\0",
         .config_verify = tuntap_verify,
+        .init = tuntap_init,
+        .drop = tuntap_drop,
         .done = tuntap_done,
         .create = netdev_create_tuntap,
         .create_type = NETDEV_CREATE_INDEPENDENT,
index 4d1e643f4313f6ee4def870943b831bde02ca9fc..88e0ce5f97047c1f0185d3eda36411f13ea487d6 100644 (file)
@@ -8,14 +8,19 @@ typedef struct TunTap TunTap;
 struct TunTap {
         NetDev meta;
 
+        int fd;
         char *user_name;
         char *group_name;
         bool multi_queue;
         bool packet_info;
         bool vnet_hdr;
+        bool keep_fd;
 };
 
 DEFINE_NETDEV_CAST(TUN, TunTap);
 DEFINE_NETDEV_CAST(TAP, TunTap);
 extern const NetDevVTable tun_vtable;
 extern const NetDevVTable tap_vtable;
+
+int manager_add_tuntap_fd(Manager *m, int fd, const char *name);
+void manager_clear_unmanaged_tuntap_fds(Manager *m);
index ccb4a426faea04c1d915401532dff8c6810fcd0e..1e6371c1effcb234c5fa46d283a8072316288022 100644 (file)
@@ -143,13 +143,13 @@ Address *address_free(Address *address) {
 bool address_is_ready(const Address *a) {
         assert(a);
 
-        if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
+        if (!ipv4acd_bound(a))
                 return false;
 
-        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
+        if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
                 return false;
 
-        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
+        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
                 return false;
 
         if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
@@ -1089,7 +1089,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) {
         if (!link_is_ready_to_configure(link, false))
                 return false;
 
-        if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
+        if (!ipv4acd_bound(address))
                 return false;
 
         /* Refuse adding more than the limit */
@@ -1190,6 +1190,7 @@ int link_request_address(
         } else {
                 existing->source = address->source;
                 existing->provider = address->provider;
+                existing->duplicate_address_detection = address->duplicate_address_detection;
                 existing->lifetime_valid_usec = address->lifetime_valid_usec;
                 existing->lifetime_preferred_usec = address->lifetime_preferred_usec;
                 if (consume_object)
index 0237c1cb98c51d42cf8b1967d1d66d501f8ca444..f97342504cf452cae5fe50638b433d9d0e521d92 100644 (file)
@@ -58,6 +58,7 @@ struct Address {
          * To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
         AddressFamily duplicate_address_detection;
         sd_ipv4acd *acd;
+        bool acd_bound;
 
         /* Called when address become ready */
         address_ready_callback_t callback;
@@ -118,12 +119,6 @@ int network_drop_invalid_addresses(Network *network);
 int address_compare_func(const Address *a1, const Address *a2);
 
 DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
-static inline void address_enter_probing(Address *address) {
-        address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
-}
-static inline void address_cancel_probing(Address *address) {
-        address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
-}
 
 void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
 
index ce5262fcd6907c8337c98c1204004f4095bb024a..94771278855ed748a385afe1eb31f69825740e8b 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/if_arp.h>
 
 #include "bus-error.h"
+#include "bus-locator.h"
 #include "dhcp-identifier.h"
 #include "dhcp-internal.h"
 #include "dhcp6-internal.h"
@@ -187,12 +188,10 @@ int manager_request_product_uuid(Manager *m) {
 
         m->product_uuid_requested = false;
 
-        r = sd_bus_call_method_async(
+        r = bus_call_method_async(
                         m->bus,
                         NULL,
-                        "org.freedesktop.hostname1",
-                        "/org/freedesktop/hostname1",
-                        "org.freedesktop.hostname1",
+                        bus_hostname,
                         "GetProductUUID",
                         get_product_uuid_handler,
                         m,
index 3795fb32f3faea0c8506297c0adae8e5f60729f7..4df2848c546718afd9203470f9d346e6db5f815e 100644 (file)
@@ -1506,6 +1506,7 @@ static int dhcp4_configure(Link *link) {
 }
 
 int dhcp4_update_mac(Link *link) {
+        bool restart;
         int r;
 
         assert(link);
@@ -1513,13 +1514,30 @@ int dhcp4_update_mac(Link *link) {
         if (!link->dhcp_client)
                 return 0;
 
-        r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.bytes,
+        restart = sd_dhcp_client_is_running(link->dhcp_client);
+
+        r = sd_dhcp_client_stop(link->dhcp_client);
+        if (r < 0)
+                return r;
+
+        r = sd_dhcp_client_set_mac(link->dhcp_client,
+                                   link->hw_addr.bytes,
                                    link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
                                    link->hw_addr.length, link->iftype);
         if (r < 0)
                 return r;
 
-        return dhcp4_set_client_identifier(link);
+        r = dhcp4_set_client_identifier(link);
+        if (r < 0)
+                return r;
+
+        if (restart) {
+                r = sd_dhcp_client_start(link->dhcp_client);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
 }
 
 int dhcp4_start(Link *link) {
index 4f2563ff9cf8e45e55a7ca3dd112f6f04014c839..a6335754448ada7d477a1aa6947bdb788fa5dbb8 100644 (file)
@@ -39,15 +39,41 @@ bool link_ipv4acd_supported(Link *link) {
         return true;
 }
 
+static bool address_ipv4acd_enabled(Address *address) {
+        assert(address);
+        assert(address->link);
+
+        if (address->family != AF_INET)
+                return false;
+
+        if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
+                return false;
+
+        /* Currently, only static and DHCP4 addresses are supported. */
+        if (!IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4))
+                return false;
+
+        if (!link_ipv4acd_supported(address->link))
+                return false;
+
+        return true;
+}
+
+bool ipv4acd_bound(const Address *address) {
+        assert(address);
+
+        if (!address->acd)
+                return true;
+
+        return address->acd_bound;
+}
+
 static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
         int r;
 
         assert(link);
         assert(address);
 
-        /* Prevent form the address being freed. */
-        address_enter_probing(address);
-
         if (!address_exists(address))
                 return 0; /* Not assigned. */
 
@@ -85,9 +111,6 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
 
-        /* make the address will be freed. */
-        address_cancel_probing(address);
-
         /* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
         return 0;
 }
@@ -108,6 +131,8 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
 
         switch (event) {
         case SD_IPV4ACD_EVENT_STOP:
+                address->acd_bound = false;
+
                 if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
                         r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
                         if (r < 0)
@@ -119,13 +144,15 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
                 break;
 
         case SD_IPV4ACD_EVENT_BIND:
+                address->acd_bound = true;
+
                 log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
                                IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
-
-                address_cancel_probing(address);
                 break;
 
         case SD_IPV4ACD_EVENT_CONFLICT:
+                address->acd_bound = false;
+
                 log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
                                  IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
 
@@ -157,31 +184,39 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void
         return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
 }
 
-int ipv4acd_configure(Address *address) {
-        Link *link;
-        int r;
-
+static int address_ipv4acd_start(Address *address) {
         assert(address);
+        assert(address->link);
 
-        link = ASSERT_PTR(address->link);
-
-        if (address->family != AF_INET)
+        if (!address->acd)
                 return 0;
 
-        if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
+        if (sd_ipv4acd_is_running(address->acd))
                 return 0;
 
-        if (!link_ipv4acd_supported(link))
+        if (!link_has_carrier(address->link))
                 return 0;
 
-        /* Currently, only static and DHCP4 addresses are supported. */
-        assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
+        return sd_ipv4acd_start(address->acd, true);
+}
 
-        if (address->acd) {
-                address_enter_probing(address);
+int ipv4acd_configure(Address *address) {
+        Link *link;
+        int r;
+
+        assert(address);
+
+        link = ASSERT_PTR(address->link);
+
+        if (!address_ipv4acd_enabled(address)) {
+                address->acd = sd_ipv4acd_unref(address->acd);
+                address->acd_bound = false;
                 return 0;
         }
 
+        if (address->acd)
+                return address_ipv4acd_start(address);
+
         log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
                        IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
 
@@ -213,14 +248,7 @@ int ipv4acd_configure(Address *address) {
         if (r < 0)
                 return r;
 
-        if (link_has_carrier(link)) {
-                r = sd_ipv4acd_start(address->acd, true);
-                if (r < 0)
-                        return r;
-        }
-
-        address_enter_probing(address);
-        return 0;
+        return address_ipv4acd_start(address);
 }
 
 int ipv4acd_update_mac(Link *link) {
@@ -255,13 +283,7 @@ int ipv4acd_start(Link *link) {
         assert(link);
 
         SET_FOREACH(address, link->addresses) {
-                if (!address->acd)
-                        continue;
-
-                if (sd_ipv4acd_is_running(address->acd))
-                        continue;
-
-                r = sd_ipv4acd_start(address->acd, true);
+                r = address_ipv4acd_start(address);
                 if (r < 0)
                         return r;
         }
index 7bd6a26b40a67abdd44cb47fbe315efff5926fd3..1ec9481b99e0256c124ece1a2f2166f78e24f457 100644 (file)
@@ -5,6 +5,7 @@ typedef struct Address Address;
 typedef struct Link Link;
 
 bool link_ipv4acd_supported(Link *link);
+bool ipv4acd_bound(const Address *address);
 int ipv4acd_configure(Address *address);
 int ipv4acd_update_mac(Link *link);
 int ipv4acd_start(Link *link);
index 20eb43eb0949c35a83b46828f7d68d16d192d80b..06e9822251385d8e9521b808dbc57a9bb6338cee 100644 (file)
@@ -64,6 +64,7 @@
 #include "strv.h"
 #include "tc.h"
 #include "tmpfile-util.h"
+#include "tuntap.h"
 #include "udev-util.h"
 #include "util.h"
 #include "vrf.h"
index 265c7e62c67a1bb3d0df071bc4b3aa4d07cdab25..52c62d72978c9cfa99f51cf9af0075245f90abb7 100644 (file)
@@ -8,15 +8,16 @@
 #include <linux/nexthop.h>
 #include <linux/nl80211.h>
 
-#include "sd-daemon.h"
 #include "sd-netlink.h"
 
 #include "alloc-util.h"
 #include "bus-error.h"
+#include "bus-locator.h"
 #include "bus-log-control-api.h"
 #include "bus-polkit.h"
 #include "bus-util.h"
 #include "conf-parser.h"
+#include "daemon-util.h"
 #include "def.h"
 #include "device-private.h"
 #include "device-util.h"
@@ -57,6 +58,7 @@
 #include "sysctl-util.h"
 #include "tclass.h"
 #include "tmpfile-util.h"
+#include "tuntap.h"
 #include "udev-util.h"
 
 /* use 128 MB for receive socket kernel queue. */
@@ -242,22 +244,45 @@ static int manager_connect_udev(Manager *m) {
         return 0;
 }
 
-static int systemd_netlink_fd(void) {
-        int n, fd, rtnl_fd = -EINVAL;
+static int manager_listen_fds(Manager *m, int *ret_rtnl_fd) {
+        _cleanup_strv_free_ char **names = NULL;
+        int n, rtnl_fd = -1;
 
-        n = sd_listen_fds(true);
-        if (n <= 0)
+        assert(m);
+        assert(ret_rtnl_fd);
+
+        n = sd_listen_fds_with_names(/* unset_environment = */ true, &names);
+        if (n < 0)
+                return n;
+
+        if (strv_length(names) != (size_t) n)
                 return -EINVAL;
 
-        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
+        for (int i = 0; i < n; i++) {
+                int fd = i + SD_LISTEN_FDS_START;
+
                 if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
-                        if (rtnl_fd >= 0)
-                                return -EINVAL;
+                        if (rtnl_fd >= 0) {
+                                log_debug("Received multiple netlink socket, ignoring.");
+                                safe_close(fd);
+                                continue;
+                        }
 
                         rtnl_fd = fd;
+                        continue;
                 }
 
-        return rtnl_fd;
+                if (manager_add_tuntap_fd(m, fd, names[i]) >= 0)
+                        continue;
+
+                if (m->test_mode)
+                        safe_close(fd);
+                else
+                        close_and_notify_warn(fd, names[i]);
+        }
+
+        *ret_rtnl_fd = rtnl_fd;
+        return 0;
 }
 
 static int manager_connect_genl(Manager *m) {
@@ -324,18 +349,21 @@ static int manager_setup_rtnl_filter(Manager *manager) {
         return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter);
 }
 
-static int manager_connect_rtnl(Manager *m) {
-        int fd, r;
+static int manager_connect_rtnl(Manager *m, int fd) {
+        _unused_ _cleanup_close_ int fd_close = fd;
+        int r;
 
         assert(m);
 
-        fd = systemd_netlink_fd();
+        /* This takes input fd. */
+
         if (fd < 0)
                 r = sd_netlink_open(&m->rtnl);
         else
                 r = sd_netlink_open_fd(&m->rtnl, fd);
         if (r < 0)
                 return r;
+        TAKE_FD(fd_close);
 
         /* Bump receiver buffer, but only if we are not called via socket activation, as in that
          * case systemd sets the receive buffer size for us, and the value in the .socket unit
@@ -486,6 +514,7 @@ static int manager_set_keep_configuration(Manager *m) {
 }
 
 int manager_setup(Manager *m) {
+        _cleanup_close_ int rtnl_fd = -1;
         int r;
 
         assert(m);
@@ -509,7 +538,11 @@ int manager_setup(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = manager_connect_rtnl(m);
+        r = manager_listen_fds(m, &rtnl_fd);
+        if (r < 0)
+                return r;
+
+        r = manager_connect_rtnl(m, TAKE_FD(rtnl_fd));
         if (r < 0)
                 return r;
 
@@ -599,6 +632,8 @@ Manager* manager_free(Manager *m) {
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
 
+        m->tuntap_fds_by_name = hashmap_free(m->tuntap_fds_by_name);
+
         m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
         m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
 
@@ -677,6 +712,8 @@ int manager_load_config(Manager *m) {
         if (r < 0)
                 return r;
 
+        manager_clear_unmanaged_tuntap_fds(m);
+
         r = network_load(m, &m->networks);
         if (r < 0)
                 return r;
@@ -992,12 +1029,10 @@ int manager_set_hostname(Manager *m, const char *hostname) {
                 return 0;
         }
 
-        r = sd_bus_call_method_async(
+        r = bus_call_method_async(
                         m->bus,
                         NULL,
-                        "org.freedesktop.hostname1",
-                        "/org/freedesktop/hostname1",
-                        "org.freedesktop.hostname1",
+                        bus_hostname,
                         "SetHostname",
                         set_hostname_handler,
                         m,
@@ -1041,12 +1076,10 @@ int manager_set_timezone(Manager *m, const char *tz) {
                 return 0;
         }
 
-        r = sd_bus_call_method_async(
+        r = bus_call_method_async(
                         m->bus,
                         NULL,
-                        "org.freedesktop.timedate1",
-                        "/org/freedesktop/timedate1",
-                        "org.freedesktop.timedate1",
+                        bus_timedate,
                         "SetTimezone",
                         set_timezone_handler,
                         m,
index 2191d0d9557340a7dbea70309b162d598a270fda..e16f2b854b76ff9829cce2f65dbb145089f15c18 100644 (file)
@@ -100,6 +100,8 @@ struct Manager {
         FirewallContext *fw_ctx;
 
         OrderedSet *request_queue;
+
+        Hashmap *tuntap_fds_by_name;
 };
 
 int manager_new(Manager **ret, bool test_mode);
index 4faa43b3279eddec6f86f20b8caaf09f5eb006f0..61b900ada2dfcb13df33f8e891c5ee9dca57469e 100644 (file)
@@ -550,7 +550,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         config_item_perf_lookup, network_network_gperf_lookup,
                         CONFIG_PARSE_WARN,
                         network,
-                        &network->stats_by_path);
+                        &network->stats_by_path,
+                        NULL);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
 
index 4c0d3d23c3dae4f6a4c294d2c48637848cf0c825..f9d774eee9e38331305b1f6e9efd253641c9cc88 100644 (file)
@@ -232,7 +232,7 @@ static int link_configure_fill_message(
                         return r;
 
                 if (link->network->use_bpdu >= 0) {
-                        r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->use_bpdu);
+                        r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, !link->network->use_bpdu);
                         if (r < 0)
                                 return r;
                 }
@@ -256,7 +256,7 @@ static int link_configure_fill_message(
                 }
 
                 if (link->network->allow_port_to_be_root >= 0) {
-                        r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root);
+                        r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, !link->network->allow_port_to_be_root);
                         if (r < 0)
                                 return r;
                 }
index 3d44c8fc82c9bd7787da6ef5c01897adb05b3667..5c270741bbd650d223dfbdbb7c4b6b00ee75c55e 100644 (file)
@@ -158,7 +158,7 @@ static int manager_update_sr_iov_ifindices(Manager *manager, int phys_port_ifind
         assert(phys_port_ifindex > 0);
         assert(virt_port_ifindex > 0);
 
-        /* This sets ifindices only whenn both interfaces are already managed by us. */
+        /* This sets ifindices only when both interfaces are already managed by us. */
 
         r = link_get_by_index(manager, phys_port_ifindex, &phys_link);
         if (r < 0)
index 1c0987bc3370c1049359e039171c2984face2681..aa1b5ed17207304385bf150dffb126b24590cd9c 100644 (file)
@@ -26,7 +26,6 @@ DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource)
 
 int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
         static const char* states[] = {
-                [LOG2U(NETWORK_CONFIG_STATE_PROBING)]     = "probing",
                 [LOG2U(NETWORK_CONFIG_STATE_REQUESTING)]  = "requesting",
                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)]  = "configured",
index 373184a3ed71b903fd78797619faa355db03c7d8..84fdc99958ffc0fa501483dbb19c77f93c63fcae 100644 (file)
@@ -27,14 +27,13 @@ typedef enum NetworkConfigSource {
 } NetworkConfigSource;
 
 typedef enum NetworkConfigState {
-        NETWORK_CONFIG_STATE_PROBING     = 1 << 0, /* address is probing by IPv4ACD */
-        NETWORK_CONFIG_STATE_REQUESTING  = 1 << 1, /* request is queued */
-        NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no response is received yet */
-        NETWORK_CONFIG_STATE_CONFIGURED  = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
+        NETWORK_CONFIG_STATE_REQUESTING  = 1 << 0, /* request is queued */
+        NETWORK_CONFIG_STATE_CONFIGURING = 1 << 1, /* e.g. address_configure() is called, but no response is received yet */
+        NETWORK_CONFIG_STATE_CONFIGURED  = 1 << 2, /* e.g. address_configure() is called and received a response from kernel.
                                                     * Note that address may not be ready yet, so please use address_is_ready()
                                                     * to check whether the address can be usable or not. */
-        NETWORK_CONFIG_STATE_MARKED      = 1 << 4, /* used GC'ing the old config */
-        NETWORK_CONFIG_STATE_REMOVING    = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
+        NETWORK_CONFIG_STATE_MARKED      = 1 << 3, /* used GC'ing the old config */
+        NETWORK_CONFIG_STATE_REMOVING    = 1 << 4, /* e.g. address_remove() is called, but no response is received yet */
 } NetworkConfigState;
 
 static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {
index 6aef268d1f98dd7390ed92311b88a2c124fa5880..8f8a7408a587e0a7eb8ff7b26f1babc1f746f97c 100644 (file)
@@ -353,10 +353,17 @@ static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) {
         if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
                 return false;
 
-        if (IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT)) /* TC_H_CLSACT == TC_H_INGRESS */
-                return true;
+        /* TC_H_CLSACT == TC_H_INGRESS */
+        if (!IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT) &&
+            link_find_tclass(link, qdisc->parent, NULL) < 0)
+                return false;
+
+        if (QDISC_VTABLE(qdisc) &&
+            QDISC_VTABLE(qdisc)->is_ready &&
+            QDISC_VTABLE(qdisc)->is_ready(qdisc, link) <= 0)
+                return false;
 
-        return link_find_tclass(link, qdisc->parent, NULL) >= 0;
+        return true;
 }
 
 static int qdisc_process_request(Request *req, Link *link, QDisc *qdisc) {
index adaaf260c471a3161a60a91d22b47d35b6523421..155e2adf24871380d532af02a3f057c7fb913f22 100644 (file)
@@ -56,6 +56,7 @@ typedef struct QDiscVTable {
         int (*init)(QDisc *qdisc);
         int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m);
         int (*verify)(QDisc *qdisc);
+        int (*is_ready)(QDisc *qdisc, Link *link);
 } QDiscVTable;
 
 extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX];
index 1422860f55dcc5825de92c17b7ad0c96bf796aa0..9fd9e090069e752d3c64232f6f749fdd679a179a 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "macro.h"
+#include "networkd-link.h"
 #include "parse-util.h"
 #include "string-util.h"
 #include "teql.h"
@@ -17,9 +18,24 @@ static int trivial_link_equalizer_verify(QDisc *qdisc) {
         return free_and_replace(qdisc->tca_kind, tca_kind);
 }
 
+static int trivial_link_equalizer_is_ready(QDisc *qdisc, Link *link) {
+        Link *teql;
+
+        assert(qdisc);
+        assert(qdisc->tca_kind);
+        assert(link);
+        assert(link->manager);
+
+        if (link_get_by_name(link->manager, qdisc->tca_kind, &teql) < 0)
+                return false;
+
+        return link_is_ready_to_configure(teql, /* allow_unmanaged = */ true);
+}
+
 const QDiscVTable teql_vtable = {
         .object_size = sizeof(TrivialLinkEqualizer),
         .verify = trivial_link_equalizer_verify,
+        .is_ready = trivial_link_equalizer_is_ready,
 };
 
 int config_parse_trivial_link_equalizer_id(
index 60cb007baa9e43a997c3c113687590a2eec90e4f..d5af73a3cdaf2f4f881ccc5a19174b5cb498db17 100644 (file)
@@ -581,7 +581,7 @@ int mount_all(const char *dest,
                   MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO|MOUNT_MKDIR },    /* skipped if above was mounted */
                 { "sysfs",                  "/sys",                         "sysfs", NULL,                             MS_NOSUID|MS_NOEXEC|MS_NODEV,
                   MOUNT_FATAL|MOUNT_MKDIR },                          /* skipped if above was mounted */
-                { "tmpfs",                  "/dev",                         "tmpfs", "mode=755" TMPFS_LIMITS_DEV,      MS_NOSUID|MS_STRICTATIME,
+                { "tmpfs",                  "/dev",                         "tmpfs", "mode=755" TMPFS_LIMITS_PRIVATE_DEV, MS_NOSUID|MS_STRICTATIME,
                   MOUNT_FATAL|MOUNT_MKDIR },
                 { "tmpfs",                  "/dev/shm",                     "tmpfs", "mode=1777" NESTED_TMPFS_LIMITS,  MS_NOSUID|MS_NODEV|MS_STRICTATIME,
                   MOUNT_FATAL|MOUNT_MKDIR },
index b41e3663098544f6525b8902ddd4689c7e48b47e..f4c196ee10db3472a99bfd314ef1b5c0ad2e368e 100644 (file)
@@ -38,6 +38,11 @@ static const sd_bus_vtable manager_vtable[] = {
                                  SD_BUS_PARAM(fd),
                                  bus_method_dump_by_fd,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_SIGNAL_WITH_NAMES("Killed",
+                                 "ss",
+                                 SD_BUS_PARAM(cgroup)
+                                 SD_BUS_PARAM(reason),
+                                 0),
         SD_BUS_VTABLE_END
 };
 
index a28e97a178a4b7e45337dc036a87ba3ade98a5e1..d9574fa97b2fbfa68f29f9446903b228549433f9 100644 (file)
@@ -83,7 +83,7 @@ static int process_managed_oom_message(Manager *m, uid_t uid, JsonVariant *param
 
                         r = cg_path_get_owner_uid(message.path, &cg_uid);
                         if (r < 0) {
-                                log_debug("Failed to get cgroup %s owner uid: %m", message.path);
+                                log_debug_errno(r, "Failed to get cgroup %s owner uid: %m", message.path);
                                 continue;
                         }
 
@@ -410,7 +410,7 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void
                 if (r < 0)
                         log_notice_errno(r, "Failed to kill any cgroup(s) based on swap: %m");
                 else {
-                        if (selected && r > 0)
+                        if (selected && r > 0) {
                                 log_notice("Killed %s due to memory used (%"PRIu64") / total (%"PRIu64") and "
                                            "swap used (%"PRIu64") / total (%"PRIu64") being more than "
                                            PERMYRIAD_AS_PERCENT_FORMAT_STR,
@@ -418,6 +418,16 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void
                                            m->system_context.mem_used, m->system_context.mem_total,
                                            m->system_context.swap_used, m->system_context.swap_total,
                                            PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad));
+
+                                /* send dbus signal */
+                                (void) sd_bus_emit_signal(m->bus,
+                                                          "/org/freedesktop/oom1",
+                                                          "org.freedesktop.oom1.Manager",
+                                                          "Killed",
+                                                          "ss",
+                                                          selected,
+                                                          "memory-used");
+                        }
                         return 0;
                 }
         }
@@ -524,13 +534,23 @@ static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t
                                  * it. In either case, go through the event loop again and select a new candidate if
                                  * pressure is still high. */
                                 m->mem_pressure_post_action_delay_start = usec_now;
-                                if (selected && r > 0)
+                                if (selected && r > 0) {
                                         log_notice("Killed %s due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%"
                                                    " for > %s with reclaim activity",
                                                    selected, t->path,
                                                    LOADAVG_INT_SIDE(t->memory_pressure.avg10), LOADAVG_DECIMAL_SIDE(t->memory_pressure.avg10),
                                                    LOADAVG_INT_SIDE(t->mem_pressure_limit), LOADAVG_DECIMAL_SIDE(t->mem_pressure_limit),
                                                    FORMAT_TIMESPAN(m->default_mem_pressure_duration_usec, USEC_PER_SEC));
+
+                                        /* send dbus signal */
+                                        (void) sd_bus_emit_signal(m->bus,
+                                                                  "/org/freedesktop/oom1",
+                                                                  "org.freedesktop.oom1.Manager",
+                                                                  "Killed",
+                                                                  "ss",
+                                                                  selected,
+                                                                  "memory-pressure");
+                                }
                                 return 0;
                         }
                 }
index 84e6c47d6745148b394cc262379b077803ef2c72..0c0c0de794ca7d9c96dc0f936422f0f5e4e5d6c5 100644 (file)
@@ -95,7 +95,7 @@ static bool arg_dry_run = true;
 static const char *arg_node = NULL;
 static char *arg_root = NULL;
 static char *arg_image = NULL;
-static char *arg_definitions = NULL;
+static char **arg_definitions = NULL;
 static bool arg_discard = true;
 static bool arg_can_factory_reset = false;
 static int arg_factory_reset = -1;
@@ -114,7 +114,7 @@ static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
 
@@ -133,6 +133,7 @@ typedef enum EncryptMode {
 
 struct Partition {
         char *definition_path;
+        char **drop_in_files;
 
         sd_id128_t type_uuid;
         sd_id128_t current_uuid, new_uuid;
@@ -266,6 +267,7 @@ static Partition* partition_free(Partition *p) {
         free(p->current_label);
         free(p->new_label);
         free(p->definition_path);
+        strv_free(p->drop_in_files);
 
         if (p->current_partition)
                 fdisk_unref_partition(p->current_partition);
@@ -1310,7 +1312,7 @@ static int config_parse_gpt_flags(
         return 0;
 }
 
-static int partition_read_definition(Partition *p, const char *path) {
+static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
 
         ConfigTableItem table[] = {
                 { "Partition", "Type",            config_parse_type,        0, &p->type_uuid        },
@@ -1336,13 +1338,25 @@ static int partition_read_definition(Partition *p, const char *path) {
                 {}
         };
         int r;
+        _cleanup_free_ char *filename = NULL;
+        const char* dropin_dirname;
 
-        r = config_parse(NULL, path, NULL,
-                         "Partition\0",
-                         config_item_table_lookup, table,
-                         CONFIG_PARSE_WARN,
-                         p,
-                         NULL);
+        r = path_extract_filename(path, &filename);
+        if (r < 0)
+                return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);;
+
+        dropin_dirname = strjoina(filename, ".d");
+
+        r = config_parse_many(
+                        STRV_MAKE_CONST(path),
+                        conf_file_dirs,
+                        dropin_dirname,
+                        "Partition\0",
+                        config_item_table_lookup, table,
+                        CONFIG_PARSE_WARN,
+                        p,
+                        NULL,
+                        &p->drop_in_files);
         if (r < 0)
                 return r;
 
@@ -1390,19 +1404,19 @@ static int partition_read_definition(Partition *p, const char *path) {
 
 static int context_read_definitions(
                 Context *context,
-                const char *directory,
+                char **directories,
                 const char *root) {
 
         _cleanup_strv_free_ char **files = NULL;
         Partition *last = NULL;
         int r;
+        const char *const *dirs;
 
         assert(context);
 
-        if (directory)
-                r = conf_files_list_strv(&files, ".conf", NULL, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) STRV_MAKE(directory));
-        else
-                r = conf_files_list_strv(&files, ".conf", root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char**) CONF_PATHS_STRV("repart.d"));
+        dirs = (const char* const*) (directories ?: CONF_PATHS_STRV("repart.d"));
+
+        r = conf_files_list_strv(&files, ".conf", directories ? NULL : root, CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, dirs);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate *.conf files: %m");
 
@@ -1417,7 +1431,7 @@ static int context_read_definitions(
                 if (!p->definition_path)
                         return log_oom();
 
-                r = partition_read_definition(p, *f);
+                r = partition_read_definition(p, *f, dirs);
                 if (r < 0)
                         return r;
 
@@ -1988,23 +2002,26 @@ static int context_dump_partitions(Context *context, const char *node) {
         _cleanup_(table_unrefp) Table *t = NULL;
         uint64_t sum_padding = 0, sum_size = 0;
         int r;
+        const size_t dropin_files_col = 13;
+        bool no_dropin_files = true;
 
         if ((arg_json_format_flags & JSON_FORMAT_OFF) && context->n_partitions == 0) {
                 log_info("Empty partition table.");
                 return 0;
         }
 
-        t = table_new("type", "label", "uuid", "file", "node", "offset", "old size", "raw size", "size", "old padding", "raw padding", "padding", "activity");
+        t = table_new("type", "label", "uuid", "file", "node", "offset", "old size", "raw size", "size", "old padding", "raw padding", "padding", "activity", "drop-in files");
         if (!t)
                 return log_oom();
 
         if (!DEBUG_LOGGING) {
                 if (arg_json_format_flags & JSON_FORMAT_OFF)
                         (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
-                                                    (size_t) 8, (size_t) 11);
+                                                    (size_t) 8, (size_t) 11, dropin_files_col);
                 else
                         (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4,
-                                                    (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12);
+                                                    (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12,
+                                                    dropin_files_col);
         }
 
         (void) table_set_align_percent(t, table_get_cell(t, 0, 5), 100);
@@ -2058,9 +2075,12 @@ static int context_dump_partitions(Context *context, const char *node) {
                                 TABLE_UINT64, p->current_padding == UINT64_MAX ? 0 : p->current_padding,
                                 TABLE_UINT64, p->new_padding,
                                 TABLE_STRING, padding_change, TABLE_SET_COLOR, !p->partitions_next && sum_padding > 0 ? ansi_underline() : NULL,
-                                TABLE_STRING, activity ?: "unchanged");
+                                TABLE_STRING, activity ?: "unchanged",
+                                TABLE_STRV, p->drop_in_files);
                 if (r < 0)
                         return table_log_add_error(r);
+
+                no_dropin_files = no_dropin_files && strv_isempty(p->drop_in_files);
         }
 
         if ((arg_json_format_flags & JSON_FORMAT_OFF) && (sum_padding > 0 || sum_size > 0)) {
@@ -2083,11 +2103,18 @@ static int context_dump_partitions(Context *context, const char *node) {
                                 TABLE_EMPTY,
                                 TABLE_EMPTY,
                                 TABLE_STRING, b,
+                                TABLE_EMPTY,
                                 TABLE_EMPTY);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
+        if (no_dropin_files) {
+                r = table_hide_column_from_display(t, dropin_files_col);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set columns to display: %m");
+        }
+
         return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
 }
 
@@ -4252,11 +4279,15 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_pretty = r;
                         break;
 
-                case ARG_DEFINITIONS:
-                        r = parse_path_argument(optarg, false, &arg_definitions);
+                case ARG_DEFINITIONS: {
+                        _cleanup_free_ char *path = NULL;
+                        r = parse_path_argument(optarg, false, &path);
                         if (r < 0)
                                 return r;
+                        if (strv_consume(&arg_definitions, TAKE_PTR(path)) < 0)
+                                return log_oom();
                         break;
+                }
 
                 case ARG_SIZE: {
                         uint64_t parsed, rounded;
@@ -4875,6 +4906,8 @@ static int run(int argc, char *argv[]) {
         if (!context)
                 return log_oom();
 
+        strv_uniq(arg_definitions);
+
         r = context_read_definitions(context, arg_definitions, arg_root);
         if (r < 0)
                 return r;
index 2b9bebbe8ccc5fbe1986986399c027860ae4f06a..1aac7ac10810e09010717254452e73a35ab06f9d 100755 (executable)
@@ -222,3 +222,110 @@ echo "### Testing json output ###"
 "$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=help
 "$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=pretty
 "$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=short
+
+echo "### Testing drop-in overrides ###"
+
+mkdir -p "$D/definitions-overrides"
+
+cat >"$D/definitions-overrides/root.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=64M
+UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
+EOF
+
+mkdir -p "$D/definitions-overrides/root.conf.d"
+
+cat >"$D/definitions-overrides/root.conf.d/override1.conf" <<EOF
+[Partition]
+Label=label1
+SizeMaxBytes=32M
+EOF
+
+cat >"$D/definitions-overrides/root.conf.d/override2.conf" <<EOF
+[Partition]
+Label=label2
+EOF
+
+rm -f test-drop-in-image
+
+JSON_OUTPUT=$("$repart" --definitions="$D/definitions-overrides" --dry-run=yes --empty=create --size=100M --json=pretty test-drop-in-image)
+
+diff <(echo "$JSON_OUTPUT") - <<EOF
+[
+       {
+               "type" : "swap",
+               "label" : "label2",
+               "uuid" : "837c3d67-21b3-478e-be82-7e7f83bf96d3",
+               "file" : "root.conf",
+               "node" : "test-drop-in-image1",
+               "offset" : 1048576,
+               "old_size" : 0,
+               "raw_size" : 33554432,
+               "old_padding" : 0,
+               "raw_padding" : 0,
+               "activity" : "create",
+               "drop-in_files" : [
+                       "$D/definitions-overrides/root.conf.d/override1.conf",
+                       "$D/definitions-overrides/root.conf.d/override2.conf"
+               ]
+       }
+]
+EOF
+
+echo "### Testing list of definitions directories ###"
+
+mkdir -p "$D/definitions1"
+
+cat >"$D/definitions1/root1.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=32M
+UUID=7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0
+Label=label1
+EOF
+
+mkdir -p "$D/definitions2"
+
+cat >"$D/definitions2/root2.conf" <<EOF
+[Partition]
+Type=swap
+SizeMaxBytes=32M
+UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
+Label=label2
+EOF
+
+rm -f test-definitions
+
+JSON_OUTPUT=$("$repart" --definitions="$D/definitions1" --definitions="$D/definitions2" --dry-run=yes --empty=create --size=100M --json=pretty test-definitions)
+
+diff <(echo "$JSON_OUTPUT") - <<EOF
+[
+       {
+               "type" : "swap",
+               "label" : "label1",
+               "uuid" : "7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0",
+               "file" : "root1.conf",
+               "node" : "test-definitions1",
+               "offset" : 1048576,
+               "old_size" : 0,
+               "raw_size" : 33554432,
+               "old_padding" : 0,
+               "raw_padding" : 0,
+               "activity" : "create"
+       },
+       {
+               "type" : "swap",
+               "label" : "label2",
+               "uuid" : "837c3d67-21b3-478e-be82-7e7f83bf96d3",
+               "file" : "root2.conf",
+               "node" : "test-definitions2",
+               "offset" : 34603008,
+               "old_size" : 0,
+               "raw_size" : 33554432,
+               "old_padding" : 0,
+               "raw_padding" : 0,
+               "activity" : "create"
+       }
+]
+EOF
index 0fc3a64d71c68b85ea0253197ebe755fed6bec24..c3c22220c22770c3ab4db84506edcca6f17396bc 100644 (file)
@@ -249,7 +249,7 @@ static int maybe_reload(sd_bus **bus) {
                 return bus_log_create_error(r);
 
         /* Reloading the daemon may take long, hence set a longer timeout here */
-        r = sd_bus_call(*bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+        r = sd_bus_call(*bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
 
@@ -597,11 +597,9 @@ static int maybe_start_stop_restart(sd_bus *bus, const char *path, const char *m
         if (!arg_now)
                 return 0;
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         method,
                         &error,
                         &reply,
index aaa1c497c02c8d6d4d71799778f68717ab4123b1..6d08821ecd63a9eff9cccc673995a0b9ccd05608 100644 (file)
@@ -138,7 +138,7 @@ int ifname_resolvconf_mangle(const char *s) {
 
         assert(s);
 
-        dot = strchr(s, '.');
+        dot = strrchr(s, '.');
         if (dot) {
                 _cleanup_free_ char *iface = NULL;
 
index 84193eacc1d7ea2c5db0cd81c126392d44303895..464892a8fe03ce411ef056cd256e994d3e67a983 100644 (file)
@@ -93,6 +93,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
                         config_item_perf_lookup, resolved_dnssd_gperf_lookup,
                         CONFIG_PARSE_WARN,
                         service,
+                        NULL,
                         NULL);
         if (r < 0)
                 return r;
index 2ae629f595861354bac0d4e8662bd5e34781dd54..4cb4478cf8fe82020881256ccc07bb4749d2dfd8 100644 (file)
@@ -643,11 +643,7 @@ static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **p
                         return bus_log_create_error(r);
         }
 
-        r = bus_append_unit_property_assignment_many(m, t, properties);
-        if (r < 0)
-                return r;
-
-        return 0;
+        return bus_append_unit_property_assignment_many(m, t, properties);
 }
 
 static int transient_cgroup_set_properties(sd_bus_message *m) {
index 3754d1dd68c88bac49f31f5a1890ce1d85b12bf9..5b9a6dbc438f681e5e817b361a8487206939ed88 100644 (file)
@@ -63,6 +63,12 @@ const BusLocator* const bus_timedate = &(BusLocator){
         .interface = "org.freedesktop.timedate1"
 };
 
+const BusLocator* const bus_hostname = &(BusLocator){
+        .destination = "org.freedesktop.hostname1",
+        .path = "/org/freedesktop/hostname1",
+        .interface = "org.freedesktop.hostname1"
+};
+
 /* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface strings encapsulated
  * within a single struct. */
 int bus_call_method_async(
index fe3b8765279312d25d234f06f30049ed5a4d675d..9662c906e18d72fba31952cd138ff30d4b3fdb6a 100644 (file)
@@ -19,6 +19,7 @@ extern const BusLocator* const bus_portable_mgr;
 extern const BusLocator* const bus_resolve_mgr;
 extern const BusLocator* const bus_systemd_mgr;
 extern const BusLocator* const bus_timedate;
+extern const BusLocator* const bus_hostname;
 
 /* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface strings encapsulated
  * within a single struct. */
index 737bbd3d36c1402e377885250fad4b39549f5426..27b6f88cd0557388b51f739c6899f2b45b7f97c0 100644 (file)
@@ -151,7 +151,10 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
 
                         bus_print_property_value(name, expected_value, flags, s);
 
-                } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
+                } else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight") && u == CGROUP_WEIGHT_IDLE)
+                        bus_print_property_value(name, expected_value, flags, "idle");
+
+                else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
                            (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
                            (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
                            (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) ||
index 3693fd61dc0dc9bbf4ff739df481952009f02f3b..56d522a7d050b1ba9d122990f6c4a19c8bc2ef0d 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include "bus-locator.h"
 #include "bus-unit-procs.h"
 #include "glyph-util.h"
 #include "hashmap.h"
@@ -344,11 +345,9 @@ int unit_show_processes(
 
         prefix = strempty(prefix);
 
-        r = sd_bus_call_method(
+        r = bus_call_method(
                         bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "GetUnitProcesses",
                         error,
                         &reply,
index 1c96519b55ed2a34a7242213ab1fbe54a3cfb2c8..2bf0d855b194ce361f5e3fb000b4b3b587168445 100644 (file)
@@ -130,6 +130,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
+DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string);
 DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
 DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
@@ -466,8 +467,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 return bus_append_parse_boolean(m, field, eq);
 
         if (STR_IN_SET(field, "CPUWeight",
-                              "StartupCPUWeight",
-                              "IOWeight",
+                              "StartupCPUWeight"))
+                return bus_append_cg_cpu_weight_parse(m, field, eq);
+
+        if (STR_IN_SET(field, "IOWeight",
                               "StartupIOWeight"))
                 return bus_append_cg_weight_parse(m, field, eq);
 
@@ -2637,12 +2640,10 @@ int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const cha
         case UNIT_TARGET:
         case UNIT_DEVICE:
         case UNIT_SWAP:
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Not supported unit type");
+                break;
 
         default:
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Invalid unit type");
+                assert_not_reached();
         }
 
         r = bus_append_unit_property(m, field, eq);
index a1fabc73c111e2bf6c88485b1d7b37fb225376c3..c3bf7348ffe9caa531a5e69180dffc48e28a48d1 100644 (file)
@@ -173,6 +173,12 @@ int cg_weight_parse(const char *s, uint64_t *ret) {
         return 0;
 }
 
+int cg_cpu_weight_parse(const char *s, uint64_t *ret) {
+        if (streq_ptr(s, "idle"))
+                return *ret = CGROUP_WEIGHT_IDLE;
+        return cg_weight_parse(s, ret);
+}
+
 int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
         uint64_t u;
         int r;
index 7eabce24512dedf101c27545d4a39b4946579133..95a515339d66d339711cd9528e4c5f7c23225b17 100644 (file)
@@ -12,6 +12,7 @@ bool cg_is_legacy_wanted(void);
 bool cg_is_hybrid_wanted(void);
 
 int cg_weight_parse(const char *s, uint64_t *ret);
+int cg_cpu_weight_parse(const char *s, uint64_t *ret);
 int cg_cpu_shares_parse(const char *s, uint64_t *ret);
 int cg_blkio_weight_parse(const char *s, uint64_t *ret);
 
index 765ccec5016d765a2cb9c928e58ffcfc8af0a703..887ae0dd61644621818d431a4e76a0814f51954a 100644 (file)
@@ -588,7 +588,8 @@ int config_parse_many(
                 const void *table,
                 ConfigParseFlags flags,
                 void *userdata,
-                Hashmap **ret_stats_by_path) {
+                Hashmap **ret_stats_by_path,
+                char ***ret_dropin_files) {
 
         _cleanup_strv_free_ char **files = NULL;
         int r;
@@ -602,7 +603,14 @@ int config_parse_many(
         if (r < 0)
                 return r;
 
-        return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
+        r = config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
+        if (r < 0)
+                return r;
+
+        if (ret_dropin_files)
+                *ret_dropin_files = TAKE_PTR(files);
+
+        return 0;
 }
 
 static int dropins_get_stats_by_path(
index bd57575af127c613efeb763a8b39870a73e8f633..32f2498b53e350576448db0fcbdcf3fe563cbef1 100644 (file)
@@ -112,7 +112,8 @@ int config_parse_many(
                 const void *table,
                 ConfigParseFlags flags,
                 void *userdata,
-                Hashmap **ret_stats_by_path);   /* possibly NULL */
+                Hashmap **ret_stats_by_path,  /* possibly NULL */
+                char ***ret_drop_in_files);   /* possibly NULL */
 
 int config_get_stats_by_path(
                 const char *suffix,
index 72ec992121f67b86c5f8fcfb99b6c6390fa86963..c1a9d35528dc4682ec709918e4ce354194d034e6 100644 (file)
@@ -83,6 +83,38 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
                         (char**) ret, ret_size);
 }
 
+int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed) {
+        _cleanup_(erase_and_freep) char *creds_password = NULL;
+        _cleanup_free_ char *cn = NULL;
+        int r;
+
+        /* Try to pick up the password for this account via the credentials logic */
+        cn = strjoin("passwd.hashed-password.", username);
+        if (!cn)
+                return -ENOMEM;
+
+        r = read_credential(cn, (void**) &creds_password, NULL);
+        if (r == -ENOENT) {
+                free(cn);
+                cn = strjoin("passwd.plaintext-password.", username);
+                if (!cn)
+                        return -ENOMEM;
+
+                r = read_credential(cn, (void**) &creds_password, NULL);
+                if (r < 0)
+                        log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+                else
+                        *ret_is_hashed = false;
+        } else if (r < 0)
+                log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+        else
+                *ret_is_hashed = true;
+
+        *ret_password = TAKE_PTR(creds_password);
+
+        return r;
+}
+
 #if HAVE_OPENSSL
 
 #define CREDENTIAL_HOST_SECRET_SIZE 4096
index ccbecaf58bd4a6495f59eb58d361f4c1edf64c8a..62e5c888eecf76f912987346a868e265cc74aa84 100644 (file)
@@ -44,6 +44,8 @@ typedef enum CredentialSecretFlags {
 
 int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size);
 
+int get_credential_user_password(const char *username, char **ret_password, bool *ret_is_hashed);
+
 /* The four modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of
  * both, as well as one with a fixed zero length key if TPM2 is missing (the latter of course provides no
  * authenticity or confidentiality, but is still useful for integrity protection, and makes things simpler
diff --git a/src/shared/daemon-util.c b/src/shared/daemon-util.c
new file mode 100644 (file)
index 0000000..32180a1
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "daemon-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "string-util.h"
+
+static int notify_remove_fd_warn(const char *name) {
+        int r;
+
+        assert(name);
+
+        r = sd_notifyf(/* unset_environment = */ false,
+                       "FDSTOREREMOVE=1\n"
+                       "FDNAME=%s", name);
+        if (r < 0)
+                return log_warning_errno(r,
+                                         "Failed to remove file descriptor \"%s\" from the store, ignoring: %m",
+                                         name);
+
+        return 0;
+}
+
+int notify_remove_fd_warnf(const char *format, ...) {
+        _cleanup_free_ char *p = NULL;
+        va_list ap;
+        int r;
+
+        assert(format);
+
+        va_start(ap, format);
+        r = vasprintf(&p, format, ap);
+        va_end(ap);
+        if (r < 0)
+                return log_oom();
+
+        return notify_remove_fd_warn(p);
+}
+
+int close_and_notify_warn(int fd, const char *name) {
+        if (name)
+                (void) notify_remove_fd_warn(name);
+
+        return safe_close(fd);
+}
+
+static int notify_push_fd(int fd, const char *name) {
+        _cleanup_free_ char *state = NULL;
+
+        assert(fd >= 0);
+        assert(name);
+
+        state = strjoin("FDSTORE=1\n"
+                        "FDNAME=", name);
+        if (!state)
+                return -ENOMEM;
+
+        return sd_pid_notify_with_fds(0, /* unset_environment = */ false, state, &fd, 1);
+}
+
+int notify_push_fdf(int fd, const char *format, ...) {
+        _cleanup_free_ char *name = NULL;
+        va_list ap;
+        int r;
+
+        assert(fd >= 0);
+        assert(format);
+
+        va_start(ap, format);
+        r = vasprintf(&name, format, ap);
+        va_end(ap);
+        if (r < 0)
+                return -ENOMEM;
+
+        return notify_push_fd(fd, name);
+}
index 585e4894a01365459792e54e2d41a45280e5f41f..711885bba462a89df59e61693b6f9973c069009d 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "sd-daemon.h"
 
+#include "macro.h"
+
 #define NOTIFY_READY "READY=1\n" "STATUS=Processing requests..."
 #define NOTIFY_STOPPING "STOPPING=1\n" "STATUS=Shutting down..."
 
@@ -20,3 +22,7 @@ static inline void notify_on_cleanup(const char **p) {
         if (*p)
                 (void) sd_notify(false, *p);
 }
+
+int notify_remove_fd_warnf(const char *format, ...) _printf_(1, 2);
+int close_and_notify_warn(int fd, const char *name);
+int notify_push_fdf(int fd, const char *format, ...) _printf_(2, 3);
index db87b23a71e1eeefd06fa7a4bc34159748ba716a..2da8e7ea94bec49d261fac8891d42da32d8a7b7b 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "alloc-util.h"
+#include "architecture.h"
 #include "env-util.h"
 #include "extension-release.h"
 #include "log.h"
@@ -15,7 +16,7 @@ int extension_release_validate(
                 const char *host_sysext_scope,
                 char **extension_release) {
 
-        const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
+        const char *extension_release_id = NULL, *extension_release_sysext_level = NULL, *extension_architecture = NULL;
 
         assert(name);
         assert(!isempty(host_os_release_id));
@@ -48,13 +49,30 @@ int extension_release_validate(
                 }
         }
 
+        /* When the architecture field is present and not '_any' it must match the host - for now just look at uname but in
+         * the future we could check if the kernel also supports 32 bit or binfmt has a translator set up for the architecture */
+        extension_architecture = strv_env_pairs_get(extension_release, "ARCHITECTURE");
+        if (!isempty(extension_architecture) && !streq(extension_architecture, "_any") &&
+            !streq(architecture_to_string(uname_architecture()), extension_architecture)) {
+                log_debug("Extension '%s' is for architecture '%s', but deployed on top of '%s'.",
+                          name, extension_architecture, architecture_to_string(uname_architecture()));
+                return 0;
+        }
+
         extension_release_id = strv_env_pairs_get(extension_release, "ID");
         if (isempty(extension_release_id)) {
-                log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
+                log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s' or be '_any'",
                           name, host_os_release_id);
                 return 0;
         }
 
+        /* A sysext with no host OS dependency (static binaries or scripts) can match
+         * '_any' host OS, and VERSION_ID or SYSEXT_LEVEL are not required anywhere */
+        if (streq(extension_release_id, "_any")) {
+                log_debug("Extension '%s' matches '_any' OS.", name);
+                return 1;
+        }
+
         if (!streq(host_os_release_id, extension_release_id)) {
                 log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
                           name, extension_release_id, host_os_release_id);
index 12170d3642b25ee5c2e591b47aaa6af26ad7e736..b4efcf6d0bd6e54c01dc79985a046e62b9bdf245 100644 (file)
@@ -537,7 +537,7 @@ int generator_hook_up_growfs(
                 "DefaultDependencies=no\n"
                 "BindsTo=%%i.mount\n"
                 "Conflicts=shutdown.target\n"
-                "After=%%i.mount\n"
+                "After=systemd-repart.service %%i.mount\n"
                 "Before=shutdown.target%s%s\n",
                 program_invocation_short_name,
                 target ? " " : "",
index 1ec861f76fe11b2d485f0d4264b47e739ad9e40b..6a680fb3be1b7747a5a86ee577a8134f10439e68 100644 (file)
@@ -680,7 +680,7 @@ int hwdb_query(const char *modalias, const char *root) {
         return 0;
 }
 
-bool hwdb_validate(sd_hwdb *hwdb) {
+bool hwdb_should_reload(sd_hwdb *hwdb) {
         bool found = false;
         const char* p;
         struct stat st;
index bfecddea421ac3e738cca7799a6d52dbd2ac4bec..cb93690ee8ddadb5e3e410cfffbeec6ef4793082 100644 (file)
@@ -5,6 +5,6 @@
 
 #include "sd-hwdb.h"
 
-bool hwdb_validate(sd_hwdb *hwdb);
+bool hwdb_should_reload(sd_hwdb *hwdb);
 int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool compat);
 int hwdb_query(const char *modalias, const char *root);
index 598a64593b533fe122442bfd373d47085ef91cc5..426a87b70cffe9844164612cdef9c4a900e53f18 100644 (file)
@@ -85,6 +85,7 @@ shared_sources = files(
         'creds-util.h',
         'cryptsetup-util.c',
         'cryptsetup-util.h',
+        'daemon-util.c',
         'daemon-util.h',
         'data-fd-util.c',
         'data-fd-util.h',
index 960d586ba990604b1d19f93af1aea6af0971d55f..1797b8803c6a3310d1668e414c5e20a38e660add 100644 (file)
 #include "errno-util.h"
 #include "macro.h"
 
-/* 4MB for contents of regular files, 1m inodes for directories, symbolic links and device nodes, using
- * large storage array systems as a baseline */
-#define TMPFS_LIMITS_DEV             ",size=4m,nr_inodes=1m"
+/* The limit used for /dev itself. 4MB should be enough since device nodes and symlinks don't
+ * consume any space and udev isn't supposed to create regular file either. There's no limit on the
+ * max number of inodes since such limit is hard to guess especially on large storage array
+ * systems. */
+#define TMPFS_LIMITS_DEV             ",size=4m"
+
+/* The limit used for /dev in private namespaces. 4MB for contents of regular files. The number of
+ * inodes should be relatively low in private namespaces but for now use a 64k limit. */
+#define TMPFS_LIMITS_PRIVATE_DEV     ",size=4m,nr_inodes=64k"
 
 /* Very little, if any use expected */
 #define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"
index e95072e048904ab9e56fd18510acbb891972a37a..18748e537627376c612e303cb8b24cd47bb8979c 100644 (file)
@@ -24,6 +24,7 @@ static const NamingScheme naming_schemes[] = {
         { "v249", NAMING_V249 },
         { "v250", NAMING_V250 },
         { "v251", NAMING_V251 },
+        { "v252", NAMING_V252 },
         /* … add more schemes here, as the logic to name devices is updated … */
 
         EXTRA_NET_NAMING_MAP
index 5303348e063e832474b723b4801843b24452323f..4fa917096907c305e1aa77f17dc6af4ddc747d47 100644 (file)
@@ -37,6 +37,7 @@ typedef enum NamingSchemeFlags {
         NAMING_REPLACE_STRICTLY          = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
         NAMING_XEN_VIF                   = 1 << 13, /* Generate names for Xen netfront devices */
         NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */
+        NAMING_DEVICETREE_ALIASES        = 1 << 15, /* Generate names from devicetree aliases */
 
         /* And now the masks that combine the features above */
         NAMING_V238 = 0,
@@ -49,6 +50,7 @@ typedef enum NamingSchemeFlags {
         NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
         NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
         NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
+        NAMING_V252 = NAMING_V251 | NAMING_DEVICETREE_ALIASES,
 
         EXTRA_NET_NAMING_SCHEMES
 
index b18f6bf3f48d46864f2cf20a39b28905331234a0..d9923e9de8fb367d01fe68cc8814b9338c4cc93d 100644 (file)
 #include <syslog.h>
 #include <unistd.h>
 
+#include "sd-device.h"
+
 #include "alloc-util.h"
 #include "blockdev-util.h"
 #include "btrfs-util.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "device-util.h"
 #include "devnum-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "strv.h"
 #include "time-util.h"
 
+#define BATTERY_LOW_CAPACITY_LEVEL 5
 #define DISCHARGE_RATE_FILEPATH "/var/lib/systemd/sleep/battery_discharge_percentage_rate_per_hour"
 #define BATTERY_DISCHARGE_RATE_HASH_KEY SD_ID128_MAKE(5f,9a,20,18,38,76,46,07,8d,36,58,0b,bb,c4,e0,63)
 
+static void *CAPACITY_TO_PTR(int capacity) {
+        assert(capacity >= 0);
+        assert(capacity <= 100);
+        return INT_TO_PTR(capacity + 1);
+}
+
+static int PTR_TO_CAPACITY(void *p) {
+        int capacity = PTR_TO_INT(p) - 1;
+        assert(capacity >= 0);
+        assert(capacity <= 100);
+        return capacity;
+}
+
 int parse_sleep_config(SleepConfig **ret_sleep_config) {
         _cleanup_(free_sleep_configp) SleepConfig *sc = NULL;
         int allow_suspend = -1, allow_hibernate = -1,
@@ -108,77 +125,177 @@ int parse_sleep_config(SleepConfig **ret_sleep_config) {
         return 0;
 }
 
-/* If battery percentage capacity is less than equal to 5% return success */
-int battery_is_low(void) {
+/* Get the list of batteries */
+static int battery_enumerator_new(sd_device_enumerator **ret) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
         int r;
 
-         /* We have not used battery capacity_level since value is set to full
-         * or Normal in case acpi is not working properly. In case of no battery
-         * 0 will be returned and system will be suspended for 1st cycle then hibernated */
+        assert(ret);
 
-        r = read_battery_capacity_percentage();
-        if (r == -ENOENT)
-               return false;
+        r = sd_device_enumerator_new(&e);
+        if (r < 0)
+                return r;
+
+        r = sd_device_enumerator_add_match_subsystem(e, "power_supply", /* match= */ true);
+        if (r < 0)
+                return r;
+
+        r = sd_device_enumerator_add_match_property(e, "POWER_SUPPLY_TYPE", "Battery");
         if (r < 0)
-               return r;
+                return r;
+
+        *ret = TAKE_PTR(e);
 
-        return r <= 5;
+        return 0;
+}
+
+static int get_capacity_by_name(Hashmap *capacities_by_name, const char *name) {
+        void *p;
+
+        assert(capacities_by_name);
+        assert(name);
+
+        p = hashmap_get(capacities_by_name, name);
+        if (!p)
+                return -ENOENT;
+
+        return PTR_TO_CAPACITY(p);
 }
 
 /* Battery percentage capacity fetched from capacity file and if in range 0-100 then returned */
-int read_battery_capacity_percentage(void) {
-        _cleanup_free_ char *bat_cap = NULL;
+static int read_battery_capacity_percentage(sd_device *dev) {
+        const char *power_supply_capacity;
         int battery_capacity, r;
 
-        r = read_one_line_file("/sys/class/power_supply/BAT0/capacity", &bat_cap);
-        if (r == -ENOENT)
-               return log_debug_errno(r, "/sys/class/power_supply/BAT0/capacity is unavailable. Assuming no battery exists: %m");
+        assert(dev);
+
+        r = sd_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY", &power_supply_capacity);
         if (r < 0)
-               return log_debug_errno(r, "Failed to read /sys/class/power_supply/BAT0/capacity: %m");
+                return log_device_debug_errno(dev, r, "Failed to read battery capacity: %m");
 
-        r = safe_atoi(bat_cap, &battery_capacity);
+        r = safe_atoi(power_supply_capacity, &battery_capacity);
         if (r < 0)
-               return log_debug_errno(r, "Failed to parse battery capacity: %m");
+                return log_device_debug_errno(dev, r, "Failed to parse battery capacity: %m");
 
         if (battery_capacity < 0 || battery_capacity > 100)
-               return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery capacity");
+                return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid battery capacity");
 
         return battery_capacity;
 }
 
-/* Read file path and return hash of value in that file */
-static int get_battery_identifier(const char *filepath, struct siphash *ret) {
-        _cleanup_free_ char *value = NULL;
+/* If battery percentage capacity is less than equal to 5% return success */
+int battery_is_low(void) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        int r;
+
+         /* We have not used battery capacity_level since value is set to full
+         * or Normal in case acpi is not working properly. In case of no battery
+         * 0 will be returned and system will be suspended for 1st cycle then hibernated */
+
+        r = battery_enumerator_new(&e);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                r = read_battery_capacity_percentage(dev);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to get battery capacity, ignoring: %m");
+                        continue;
+                }
+                if (r > BATTERY_LOW_CAPACITY_LEVEL)
+                        return false;
+        }
+
+        return true;
+}
+
+/* Store current capacity of each battery before suspension and timestamp */
+int fetch_batteries_capacity_by_name(Hashmap **ret) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        _cleanup_(hashmap_freep) Hashmap *batteries_capacity_by_name = NULL;
+        sd_device *dev;
         int r;
 
-        assert(filepath);
         assert(ret);
 
-        r = read_one_line_file(filepath, &value);
+        batteries_capacity_by_name = hashmap_new(&string_hash_ops_free);
+        if (!batteries_capacity_by_name)
+                return log_oom_debug();
+
+        r = battery_enumerator_new(&e);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                _cleanup_free_ char *battery_name_copy = NULL;
+                const char *battery_name;
+                int battery_capacity;
+
+                battery_capacity = r = read_battery_capacity_percentage(dev);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to get battery capacity, ignoring: %m");
+                        continue;
+                }
+
+                r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+                        continue;
+                }
+
+                battery_name_copy = strdup(battery_name);
+                if (!battery_name_copy)
+                        return log_oom_debug();
+
+                r = hashmap_put(batteries_capacity_by_name, battery_name_copy, CAPACITY_TO_PTR(battery_capacity));
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to store battery capacity: %m");
+
+                TAKE_PTR(battery_name_copy);
+        }
+
+        *ret = TAKE_PTR(batteries_capacity_by_name);
+
+        return 0;
+}
+
+/* Read file path and return hash of value in that file */
+static int get_battery_identifier(sd_device *dev, const char *property, struct siphash *state) {
+        const char *x;
+        int r;
+
+        assert(dev);
+        assert(property);
+        assert(state);
+
+        r = sd_device_get_property_value(dev, property, &x);
         if (r == -ENOENT)
-               log_debug_errno(r, "%s is unavailable: %m", filepath);
+               log_device_debug_errno(dev, r, "battery device property %s is unavailable, ignoring: %m", property);
         else if (r < 0)
-               return log_debug_errno(r, "Failed to read %s: %m", filepath);
-        else if (isempty(value))
-               log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "%s is empty: %m", filepath);
+               return log_device_debug_errno(dev, r, "Failed to read battery device property %s: %m", property);
+        else if (isempty(x))
+               log_device_debug(dev, "battery device property '%s' is null.", property);
         else
-               siphash24_compress_string(value, ret);
+               siphash24_compress_string(x, state);
 
         return 0;
 }
 
 /* Read system and battery identifier from specific location and generate hash of it */
-static int get_system_battery_identifier_hash(uint64_t *ret_hash) {
+static int get_system_battery_identifier_hash(sd_device *dev, uint64_t *ret) {
         struct siphash state;
         sd_id128_t machine_id, product_id;
         int r;
 
-        assert(ret_hash);
+        assert(ret);
+        assert(dev);
 
         siphash24_init(&state, BATTERY_DISCHARGE_RATE_HASH_KEY.bytes);
-        get_battery_identifier("/sys/class/power_supply/BAT0/manufacturer", &state);
-        get_battery_identifier("/sys/class/power_supply/BAT0/model_name", &state);
-        get_battery_identifier("/sys/class/power_supply/BAT0/serial_number", &state);
+
+        get_battery_identifier(dev, "POWER_SUPPLY_MANUFACTURER", &state);
+        get_battery_identifier(dev, "POWER_SUPPLY_MODEL_NAME", &state);
+        get_battery_identifier(dev, "POWER_SUPPLY_SERIAL_NUMBER", &state);
 
         r = sd_id128_get_machine(&machine_id);
         if (r == -ENOENT)
@@ -196,7 +313,7 @@ static int get_system_battery_identifier_hash(uint64_t *ret_hash) {
         else
                siphash24_compress(&product_id, sizeof(sd_id128_t), &state);
 
-        *ret_hash = siphash24_finalize(&state);
+        *ret = siphash24_finalize(&state);
 
         return 0;
 }
@@ -208,66 +325,204 @@ static bool battery_discharge_rate_is_valid(int battery_discharge_rate) {
 
 /* Battery percentage discharge rate per hour is read from specific file. It is stored along with system
  * and battery identifier hash to maintain the integrity of discharge rate value */
-int get_battery_discharge_rate(void) {
-        _cleanup_free_ char *hash_id_discharge_rate = NULL, *stored_hash_id = NULL, *stored_discharge_rate = NULL;
+static int get_battery_discharge_rate(sd_device *dev, int *ret) {
+        _cleanup_fclose_ FILE *f = NULL;
+        uint64_t current_hash_id;
         const char *p;
-        uint64_t current_hash_id, hash_id;
-        int discharge_rate, r;
+        int r;
 
-        r = read_one_line_file(DISCHARGE_RATE_FILEPATH, &hash_id_discharge_rate);
-        if (r < 0)
-               return log_debug_errno(r, "Failed to read discharge rate from %s: %m", DISCHARGE_RATE_FILEPATH);
+        assert(dev);
+        assert(ret);
 
-        p = hash_id_discharge_rate;
-        r = extract_many_words(&p, " ", 0, &stored_hash_id, &stored_discharge_rate, NULL);
-        if (r < 0)
-               return log_debug_errno(r, "Failed to parse hash_id and discharge_rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
-        if (r != 2)
-               return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid number of items fetched from %s", DISCHARGE_RATE_FILEPATH);
+        f = fopen(DISCHARGE_RATE_FILEPATH, "re");
+        if (!f)
+                return log_debug_errno(errno, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH ": %m");
 
-        r = safe_atou64(stored_hash_id, &hash_id);
+        r = get_system_battery_identifier_hash(dev, &current_hash_id);
         if (r < 0)
-               return log_debug_errno(r, "Failed to parse discharge rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
+                return log_device_debug_errno(dev, r, "Failed to generate system battery identifier hash: %m");
 
-        r = get_system_battery_identifier_hash(&current_hash_id);
-        if (r < 0)
-               return log_debug_errno(r, "Failed to generate system battery identifier hash: %m");
+        for (;;) {
+                _cleanup_free_ char *stored_hash_id = NULL, *stored_discharge_rate = NULL, *line = NULL;
+                uint64_t hash_id;
+                int discharge_rate;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH ": %m");
+                if (r == 0)
+                        break;
 
-        if(current_hash_id != hash_id)
-               return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Current identifier does not match stored identifier: %m");
+                p = line;
+                r = extract_many_words(&p, NULL, 0, &stored_hash_id, &stored_discharge_rate, NULL);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to parse hash_id and discharge_rate read from " DISCHARGE_RATE_FILEPATH ": %m");
+                if (r != 2)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid number of items fetched from " DISCHARGE_RATE_FILEPATH);
 
-        r = safe_atoi(stored_discharge_rate, &discharge_rate);
-        if (r < 0)
-               return log_debug_errno(r, "Failed to parse discharge rate read from %s location: %m", DISCHARGE_RATE_FILEPATH);
+                r = safe_atou64(stored_hash_id, &hash_id);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to parse hash ID read from " DISCHARGE_RATE_FILEPATH " location: %m");
+
+                if (current_hash_id != hash_id)
+                        /* matching device not found, move to next line */
+                        continue;
+
+                r = safe_atoi(stored_discharge_rate, &discharge_rate);
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to parse discharge rate read from " DISCHARGE_RATE_FILEPATH ": %m");
+
+                if (!battery_discharge_rate_is_valid(discharge_rate))
+                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
 
-        if (!battery_discharge_rate_is_valid(discharge_rate))
-               return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
+                *ret = discharge_rate;
+                return 0; /* matching device found, exit iteration */
+        }
 
-        return discharge_rate;
+        return -ENOENT;
 }
 
 /* Write battery percentage discharge rate per hour along with system and battery identifier hash to file */
-int put_battery_discharge_rate(int estimated_battery_discharge_rate) {
-        uint64_t system_hash_id;
+static int put_battery_discharge_rate(int estimated_battery_discharge_rate, uint64_t system_hash_id, bool trunc) {
         int r;
 
         if (!battery_discharge_rate_is_valid(estimated_battery_discharge_rate))
-               return log_debug_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid battery discharge percentage rate per hour: %m");
+                return log_debug_errno(SYNTHETIC_ERRNO(ERANGE),
+                                        "Invalid battery discharge rate %d%% per hour: %m",
+                                        estimated_battery_discharge_rate);
 
-        r = get_system_battery_identifier_hash(&system_hash_id);
+        r = write_string_filef(
+                DISCHARGE_RATE_FILEPATH,
+                WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_MKDIR_0755 | (trunc ? WRITE_STRING_FILE_TRUNCATE : 0),
+                "%"PRIu64" %d",
+                system_hash_id,
+                estimated_battery_discharge_rate);
         if (r < 0)
-               return log_debug_errno(r, "Failed to generate system battery identifier hash: %m");
+                return log_debug_errno(r, "Failed to update %s: %m", DISCHARGE_RATE_FILEPATH);
 
-        r = write_string_filef(
-                        DISCHARGE_RATE_FILEPATH,
-                        WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755,
-                        "%"PRIu64" %d",
-                        system_hash_id,
-                        estimated_battery_discharge_rate);
+        log_debug("Estimated discharge rate %d%% per hour successfully saved to %s", estimated_battery_discharge_rate, DISCHARGE_RATE_FILEPATH);
+
+        return 0;
+}
+
+/* Estimate battery discharge rate using stored previous and current capacity over timestamp difference */
+int estimate_battery_discharge_rate_per_hour(
+                Hashmap *last_capacity,
+                Hashmap *current_capacity,
+                usec_t before_timestamp,
+                usec_t after_timestamp) {
+
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        sd_device *dev;
+        bool trunc = true;
+        int r;
+
+        assert(last_capacity);
+        assert(current_capacity);
+        assert(before_timestamp < after_timestamp);
+
+        r = battery_enumerator_new(&e);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                int battery_last_capacity, battery_current_capacity, battery_discharge_rate;
+                const char *battery_name;
+                uint64_t system_hash_id;
+
+                r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+                        continue;
+                }
+
+                battery_last_capacity = get_capacity_by_name(last_capacity, battery_name);
+                if (battery_last_capacity < 0)
+                        continue;
+
+                battery_current_capacity = get_capacity_by_name(current_capacity, battery_name);
+                if (battery_current_capacity < 0)
+                        continue;
+
+                if (battery_current_capacity >= battery_last_capacity) {
+                        log_device_debug(dev, "Battery was not discharged during suspension");
+                        continue;
+                }
+
+                r = get_system_battery_identifier_hash(dev, &system_hash_id);
+                if (r < 0)
+                        return log_device_debug_errno(dev, r, "Failed to generate system battery identifier hash: %m");
+
+                log_device_debug(dev,
+                                 "%d%% was discharged in %s. Estimating discharge rate...",
+                                 battery_last_capacity - battery_current_capacity,
+                                 FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_SEC));
+
+                battery_discharge_rate = (battery_last_capacity - battery_current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp);
+                r = put_battery_discharge_rate(battery_discharge_rate, system_hash_id, trunc);
+                if (r < 0)
+                        log_device_warning_errno(dev, r, "Failed to update battery discharge rate, ignoring: %m");
+                else
+                        trunc = false;
+        }
+
+        return 0;
+}
+
+/* calculate the suspend interval for each battery and then return the sum of it */
+int get_total_suspend_interval(Hashmap *last_capacity, usec_t *ret) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        usec_t total_suspend_interval = 0;
+        sd_device *dev;
+        int r;
+
+        assert(last_capacity);
+        assert(ret);
+
+        r = battery_enumerator_new(&e);
         if (r < 0)
-                return log_debug_errno(r, "Failed to create %s: %m", DISCHARGE_RATE_FILEPATH);
+                return log_debug_errno(r, "Failed to initialize battery enumerator: %m");
+
+        FOREACH_DEVICE(e, dev) {
+                int battery_last_capacity, previous_discharge_rate = 0;
+                const char *battery_name;
+                usec_t suspend_interval;
+
+                r = sd_device_get_property_value(dev, "POWER_SUPPLY_NAME", &battery_name);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to read battery name, ignoring: %m");
+                        continue;
+                }
+
+                battery_last_capacity = PTR_TO_CAPACITY(hashmap_get(last_capacity, battery_name));
+                if (battery_last_capacity <= 0)
+                        continue;
+
+                r = get_battery_discharge_rate(dev, &previous_discharge_rate);
+                if (r < 0) {
+                        log_device_debug_errno(dev, r, "Failed to get discharge rate, ignoring: %m");
+                        continue;
+                }
+
+                if (previous_discharge_rate == 0)
+                        continue;
+
+                if (battery_last_capacity * 2 <= previous_discharge_rate) {
+                        log_device_debug(dev, "Current battery capacity percentage too low compared to discharge rate");
+                        continue;
+                }
+                suspend_interval = battery_last_capacity * USEC_PER_HOUR / previous_discharge_rate;
+
+                total_suspend_interval = usec_add(total_suspend_interval, suspend_interval);
+        }
+        /* The previous discharge rate is stored in per hour basis so converted to minutes.
+         * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
+        total_suspend_interval = usec_sub_unsigned(total_suspend_interval, 30 * USEC_PER_MINUTE);
+        if (total_suspend_interval == 0)
+                return -ENOENT;
+
+        *ret = total_suspend_interval;
 
-        log_debug("Estimated discharge rate %d successfully updated to %s", estimated_battery_discharge_rate, DISCHARGE_RATE_FILEPATH);
         return 0;
 }
 
index a48cf17a54ec63b56111e03338201a8741de6a6f..54fe65007ede17aa0eaf3baf659411f1e34d7e92 100644 (file)
@@ -2,6 +2,8 @@
 #pragma once
 
 #include <linux/fiemap.h>
+
+#include "hashmap.h"
 #include "time-util.h"
 
 typedef enum SleepOperation {
@@ -55,10 +57,14 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location);
 int can_sleep(SleepOperation operation);
 int can_sleep_disk(char **types);
 int can_sleep_state(char **types);
-int read_battery_capacity_percentage(void);
 int battery_is_low(void);
-int get_battery_discharge_rate(void);
-int put_battery_discharge_rate(int estimated_battery_discharge_rate);
+int get_total_suspend_interval(Hashmap *last_capacity, usec_t *ret);
+int fetch_batteries_capacity_by_name(Hashmap **ret_current_capacity);
+int estimate_battery_discharge_rate_per_hour(
+                Hashmap *last_capacity,
+                Hashmap *current_capacity,
+                usec_t before_timestamp,
+                usec_t after_timestamp);
 
 const char* sleep_operation_to_string(SleepOperation s) _const_;
 SleepOperation sleep_operation_from_string(const char *s) _pure_;
index abcedde8a89d53ab7250e9f585af1d33340f3d2a..f88272db7b052c9eea89f1cd4825f78a32ee962c 100644 (file)
@@ -225,9 +225,12 @@ static int tpm2_init(const char *device, struct tpm2_context *ret) {
         return 0;
 }
 
+#define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
+
 static int tpm2_credit_random(ESYS_CONTEXT *c) {
         size_t rps, done = 0;
         TSS2_RC rc;
+        usec_t t;
         int r;
 
         assert(c);
@@ -237,6 +240,16 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) {
          * but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit
          * any entropy. */
 
+        if (access(TPM2_CREDIT_RANDOM_FLAG_PATH, F_OK) < 0) {
+                if (errno != ENOENT)
+                        log_debug_errno(errno, "Failed to detect if '" TPM2_CREDIT_RANDOM_FLAG_PATH "' exists, ignoring: %m");
+        } else {
+                log_debug("Not adding TPM2 entropy to the kernel random pool again.");
+                return 0; /* Already done */
+        }
+
+        t = now(CLOCK_MONOTONIC);
+
         for (rps = random_pool_size(); rps > 0;) {
                 _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL;
 
@@ -255,7 +268,7 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) {
                         return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
                                                "Zero-sized entropy returned from TPM.");
 
-                r = random_write_entropy(-1, buffer->buffer, buffer->size, false);
+                r = random_write_entropy(-1, buffer->buffer, buffer->size, /* credit= */ false);
                 if (r < 0)
                         return log_error_errno(r, "Failed wo write entropy to kernel: %m");
 
@@ -263,7 +276,12 @@ static int tpm2_credit_random(ESYS_CONTEXT *c) {
                 rps = LESS_BY(rps, buffer->size);
         }
 
-        log_debug("Added %zu bytes of entropy to the kernel random pool.", done);
+        log_debug("Added %zu bytes of TPM2 entropy to the kernel random pool in %s.", done, FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - t, 0));
+
+        r = touch(TPM2_CREDIT_RANDOM_FLAG_PATH);
+        if (r < 0)
+                log_debug_errno(r, "Failed to touch '" TPM2_CREDIT_RANDOM_FLAG_PATH "', ignoring: %m");
+
         return 0;
 }
 
@@ -280,17 +298,15 @@ static int tpm2_make_primary(
                         .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,
+                        .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,
                         },
                 },
         };
@@ -300,16 +316,14 @@ static int tpm2_make_primary(
                         .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,
+                        .parameters.rsaDetail = {
+                                .symmetric = {
+                                        .algorithm = TPM2_ALG_AES,
+                                        .keyBits.aes = 128,
+                                        .mode.aes = TPM2_ALG_CFB,
                                 },
+                                .scheme.scheme = TPM2_ALG_NULL,
+                                .keyBits = 2048,
                         },
                 },
         };
@@ -393,7 +407,7 @@ static int tpm2_make_primary(
         return 0;
 }
 
-static void tpm2_pcr_mask_to_selecion(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) {
+static void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret) {
         assert(ret);
 
         /* We only do 24bit here, as that's what PC TPMs are supposed to support */
@@ -401,11 +415,13 @@ static void tpm2_pcr_mask_to_selecion(uint32_t mask, uint16_t bank, TPML_PCR_SEL
 
         *ret = (TPML_PCR_SELECTION) {
                 .count = 1,
-                .pcrSelections[0].hash = bank,
-                .pcrSelections[0].sizeofSelect = 3,
-                .pcrSelections[0].pcrSelect[0] = mask & 0xFF,
-                .pcrSelections[0].pcrSelect[1] = (mask >> 8) & 0xFF,
-                .pcrSelections[0].pcrSelect[2] = (mask >> 16) & 0xFF,
+                .pcrSelections[0] = {
+                        .hash = bank,
+                        .sizeofSelect = 3,
+                        .pcrSelect[0] = mask & 0xFF,
+                        .pcrSelect[1] = (mask >> 8) & 0xFF,
+                        .pcrSelect[2] = (mask >> 16) & 0xFF,
+                }
         };
 }
 
@@ -447,7 +463,7 @@ static int tpm2_pcr_mask_good(
          * actually measure into them, or only into a suboptimal bank. If so, the PCRs should be all zero or
          * all 0xFF. Detect that, so that we can warn and maybe pick a better bank. */
 
-        tpm2_pcr_mask_to_selecion(mask, bank, &selection);
+        tpm2_pcr_mask_to_selection(mask, bank, &selection);
 
         rc = sym_Esys_PCR_Read(
                         c,
@@ -602,17 +618,13 @@ static int tpm2_get_best_pcr_bank(
 
 static int tpm2_make_encryption_session(
                 ESYS_CONTEXT *c,
-                ESYS_TR tpmKey,
+                ESYS_TR primary,
                 ESYS_TR *ret_session) {
 
         static const TPMT_SYM_DEF symmetric = {
                 .algorithm = TPM2_ALG_AES,
-                .keyBits = {
-                        .aes = 128,
-                },
-                .mode = {
-                        .aes = TPM2_ALG_CFB,
-                },
+                .keyBits.aes = 128,
+                .mode.aes = TPM2_ALG_CFB,
         };
         const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
                         TPMA_SESSION_CONTINUESESSION;
@@ -628,7 +640,7 @@ static int tpm2_make_encryption_session(
          * recover the salt, which is then used for key derivation. */
         rc = sym_Esys_StartAuthSession(
                         c,
-                        tpmKey,
+                        primary,
                         ESYS_TR_NONE,
                         ESYS_TR_NONE,
                         ESYS_TR_NONE,
@@ -663,8 +675,9 @@ static int tpm2_make_encryption_session(
 
 static int tpm2_make_pcr_session(
                 ESYS_CONTEXT *c,
-                ESYS_TR tpmKey,
+                ESYS_TR primary,
                 ESYS_TR parent_session,
+                TPM2_SE session_type,
                 uint32_t pcr_mask,
                 uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
                 bool use_pin,
@@ -674,12 +687,8 @@ static int tpm2_make_pcr_session(
 
         static const TPMT_SYM_DEF symmetric = {
                 .algorithm = TPM2_ALG_AES,
-                .keyBits = {
-                        .aes = 128
-                },
-                .mode = {
-                        .aes = TPM2_ALG_CFB,
-                }
+                .keyBits.aes = 128,
+                .mode.aes = TPM2_ALG_CFB,
         };
         _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
         TPML_PCR_SELECTION pcr_selection;
@@ -698,7 +707,7 @@ static int tpm2_make_pcr_session(
                 if (r == 0)
                         log_notice("Selected TPM2 PCRs are not initialized on this system, most likely due to a firmware issue. PCR policy is effectively not enforced. Proceeding anyway.");
 
-                tpm2_pcr_mask_to_selecion(pcr_mask, pcr_bank, &pcr_selection);
+                tpm2_pcr_mask_to_selection(pcr_mask, pcr_bank, &pcr_selection);
         } else {
                 TPMI_ALG_HASH h;
 
@@ -708,18 +717,18 @@ static int tpm2_make_pcr_session(
                 if (r < 0)
                         return r;
 
-                tpm2_pcr_mask_to_selecion(pcr_mask, h, &pcr_selection);
+                tpm2_pcr_mask_to_selection(pcr_mask, h, &pcr_selection);
         }
 
         rc = sym_Esys_StartAuthSession(
                         c,
-                        tpmKey,
+                        primary,
                         ESYS_TR_NONE,
                         parent_session,
                         ESYS_TR_NONE,
                         ESYS_TR_NONE,
                         NULL,
-                        TPM2_SE_POLICY,
+                        session_type,
                         &symmetric,
                         TPM2_ALG_SHA256,
                         &session);
@@ -888,8 +897,17 @@ int tpm2_seal(
         if (r < 0)
                 goto finish;
 
-        r = tpm2_make_pcr_session(c.esys_context, primary, session, pcr_mask, UINT16_MAX, !!pin, NULL,
-                                  &policy_digest, &pcr_bank);
+        r = tpm2_make_pcr_session(
+                        c.esys_context,
+                        primary,
+                        session,
+                        TPM2_SE_TRIAL,
+                        pcr_mask,
+                        /* pcr_bank= */ UINT16_MAX,
+                        !!pin,
+                        /* ret_session= */ NULL,
+                        &policy_digest,
+                        &pcr_bank);
         if (r < 0)
                 goto finish;
 
@@ -902,16 +920,8 @@ int tpm2_seal(
                         .type = TPM2_ALG_KEYEDHASH,
                         .nameAlg = TPM2_ALG_SHA256,
                         .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
-                        .parameters = {
-                                .keyedHashDetail = {
-                                        .scheme.scheme = TPM2_ALG_NULL,
-                                },
-                        },
-                        .unique = {
-                                .keyedHash = {
-                                        .size = 32,
-                                },
-                        },
+                        .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
+                        .unique.keyedHash.size = 32,
                         .authPolicy = *policy_digest,
                 },
         };
@@ -1101,8 +1111,17 @@ int tpm2_unseal(
         if (r < 0)
                 goto finish;
 
-        r = tpm2_make_pcr_session(c.esys_context, primary, hmac_session, pcr_mask, pcr_bank, !!pin, &session,
-                                  &policy_digest, NULL);
+        r = tpm2_make_pcr_session(
+                        c.esys_context,
+                        primary,
+                        hmac_session,
+                        TPM2_SE_POLICY,
+                        pcr_mask,
+                        pcr_bank,
+                        !!pin,
+                        &session,
+                        &policy_digest,
+                        /* ret_pcr_bank= */ NULL);
         if (r < 0)
                 goto finish;
 
index 5eed3d95fde5f6900116a4a93b03ba8059b2d9c3..0c6dea4264d8119f2d2b0c62da06a10054a58e95 100644 (file)
@@ -29,7 +29,7 @@
 
 static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = {
         [RESOLVE_NAME_NEVER] = "never",
-        [RESOLVE_NAME_LATE] = "late",
+        [RESOLVE_NAME_LATE]  = "late",
         [RESOLVE_NAME_EARLY] = "early",
 };
 
@@ -661,7 +661,7 @@ static int device_is_power_sink(sd_device *device) {
 
 int on_ac_power(void) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        bool found_offline = false, found_online = false;
+        bool found_offline = false, found_online = false, found_battery = false;
         sd_device *d;
         int r;
 
@@ -692,6 +692,7 @@ int on_ac_power(void) {
                  * for defined power source types. Also see:
                  * https://docs.kernel.org/admin-guide/abi-testing.html#abi-file-testing-sysfs-class-power */
                 if (streq(val, "Battery")) {
+                        found_battery = true;
                         log_device_debug(d, "The power supply is battery, ignoring.");
                         continue;
                 }
@@ -732,10 +733,12 @@ int on_ac_power(void) {
                 log_debug("Found at least one online non-battery power supply, system is running on AC power.");
         else if (!found_offline)
                 log_debug("Found no offline non-battery power supply, assuming system is running on AC power.");
+        else if (!found_battery)
+                log_debug("Found no battery, assuming system is running on AC power.");
         else
                 log_debug("All non-battery power supplies are offline, assuming system is running with battery.");
 
-        return found_online || !found_offline;
+        return found_online || !found_offline || !found_battery;
 }
 
 bool udev_available(void) {
index 95895a8e458dc2b645dab62c761fcda2f172e3e1..4e46a2fe3fbad1be0bd42616612ec49bf6b94097 100644 (file)
@@ -276,7 +276,9 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
         if (hr->memory_max != UINT64_MAX)
                 printf("  Memory Max: %s\n", FORMAT_BYTES(hr->memory_max));
 
-        if (hr->cpu_weight != UINT64_MAX)
+        if (hr->cpu_weight == CGROUP_WEIGHT_IDLE)
+                printf("  CPU Weight: %s\n", "idle");
+        else if (hr->cpu_weight != UINT64_MAX)
                 printf("  CPU Weight: %" PRIu64 "\n", hr->cpu_weight);
 
         if (hr->io_weight != UINT64_MAX)
index eee956d496317757a9d24712cc0a9fcc446702e4..af9697526d38eeb725b809bebce2309dac233162 100644 (file)
@@ -20,6 +20,7 @@
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "def.h"
+#include "errno-util.h"
 #include "exec-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -331,10 +332,13 @@ static void init_watchdog(void) {
 }
 
 int main(int argc, char *argv[]) {
+        static const char* const dirs[] = {
+                SYSTEM_SHUTDOWN_PATH,
+                NULL
+        };
         _cleanup_free_ char *cgroup = NULL;
         char *arguments[3];
         int cmd, r;
-        static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
 
         /* The log target defaults to console, but the original systemd process will pass its log target in through a
          * command line argument, which will override this default. Also, ensure we'll never log to the journal or
@@ -356,8 +360,7 @@ int main(int argc, char *argv[]) {
         umask(0022);
 
         if (getpid_cached() != 1) {
-                log_error("Not executed by init (PID 1).");
-                r = -EPERM;
+                r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Not executed by init (PID 1).");
                 goto error;
         }
 
@@ -372,8 +375,7 @@ int main(int argc, char *argv[]) {
         else if (streq(arg_verb, "exit"))
                 cmd = 0; /* ignored, just checking that arg_verb is valid */
         else {
-                log_error("Unknown action '%s'.", arg_verb);
-                r = -EINVAL;
+                r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'.", arg_verb);
                 goto error;
         }
 
@@ -423,10 +425,8 @@ int main(int argc, char *argv[]) {
 
                 (void) watchdog_ping();
 
-                /* Let's trim the cgroup tree on each iteration so
-                   that we leave an empty cgroup tree around, so that
-                   container managers get a nice notify event when we
-                   are down */
+                /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around,
+                 * so that container managers get a nice notify event when we are down */
                 if (cgroup)
                         (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
 
@@ -506,8 +506,7 @@ int main(int argc, char *argv[]) {
                         continue;
                 }
 
-                /* If in this iteration we didn't manage to
-                 * unmount/deactivate anything, we simply give up */
+                /* If in this iteration we didn't manage to unmount/deactivate anything, we simply give up */
                 if (!changed) {
                         log_info("Cannot finalize remaining%s%s%s%s%s continuing.",
                                  need_umount ? " file systems," : "",
@@ -526,12 +525,11 @@ int main(int argc, char *argv[]) {
                           need_md_detach ? " MD devices," : "");
         }
 
-        /* We're done with the watchdog. Note that the watchdog is explicitly not
-         * stopped here. It remains active to guard against any issues during the
-         * rest of the shutdown sequence. */
+        /* We're done with the watchdog. Note that the watchdog is explicitly not stopped here. It remains
+         * active to guard against any issues during the rest of the shutdown sequence. */
         watchdog_free_device();
 
-        arguments[0] = NULL;
+        arguments[0] = NULL; /* Filled in by execute_directories(), when needed */
         arguments[1] = arg_verb;
         arguments[2] = NULL;
         (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
@@ -563,10 +561,11 @@ int main(int argc, char *argv[]) {
                           need_dm_detach ? " DM devices," : "",
                           need_md_detach ? " MD devices," : "");
 
-        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
-         * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
-         * sync'ed things already once above, but we did some more work since then which might have caused IO, hence
-         * let's do it once more. Do not remove this sync, data corruption will result. */
+        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
+         * to be sync'ed explicitly in advance. So let's do this here, but not needlessly slow down
+         * containers. Note that we sync'ed things already once above, but we did some more work since then
+         * which might have caused IO, hence let's do it once more. Do not remove this sync, data corruption
+         * will result. */
         if (!in_container)
                 sync_with_progress();
 
@@ -596,6 +595,7 @@ int main(int argc, char *argv[]) {
                                 /* Child */
 
                                 execv(args[0], (char * const *) args);
+                                log_debug_errno(errno, "Failed to execute '" KEXEC "' binary, proceeding with reboot(RB_KEXEC): %m");
 
                                 /* execv failed (kexec binary missing?), so try simply reboot(RB_KEXEC) */
                                 (void) reboot(cmd);
@@ -626,9 +626,8 @@ int main(int argc, char *argv[]) {
         }
 
         (void) reboot(cmd);
-        if (errno == EPERM && in_container) {
-                /* If we are in a container, and we lacked
-                 * CAP_SYS_BOOT just exit, this will kill our
+        if (ERRNO_IS_PRIVILEGE(errno) && in_container) {
+                /* If we are in a container, and we lacked CAP_SYS_BOOT just exit, this will kill our
                  * container for good. */
                 log_info("Exiting container.");
                 return EXIT_SUCCESS;
index ff6c71d61b6a3a59b3be3c6117366dcb0bc6f648..14191cfc61c593c0356d4873235a3b4d9321634a 100644 (file)
@@ -263,6 +263,7 @@ static int execute(
 }
 
 static int execute_s2h(const SleepConfig *sleep_config) {
+        _cleanup_hashmap_free_ Hashmap *last_capacity = NULL, *current_capacity = NULL;
         int r;
 
         assert(sleep_config);
@@ -270,42 +271,29 @@ static int execute_s2h(const SleepConfig *sleep_config) {
         while (battery_is_low() == 0) {
                 _cleanup_close_ int tfd = -1;
                 struct itimerspec ts = {};
-                usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0;
+                usec_t suspend_interval = sleep_config->hibernate_delay_sec, before_timestamp = 0, after_timestamp = 0, total_suspend_interval;
                 bool woken_by_timer;
-                int last_capacity = 0, current_capacity = 0, previous_discharge_rate, estimated_discharge_rate = 0;
 
                 tfd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK|TFD_CLOEXEC);
                 if (tfd < 0)
                         return log_error_errno(errno, "Error creating timerfd: %m");
 
                 /* Store current battery capacity and current time before suspension */
-                r = read_battery_capacity_percentage();
-                if (r >= 0) {
-                        last_capacity = r;
-                        log_debug("Current battery charge percentage: %d%%", last_capacity);
+                r = fetch_batteries_capacity_by_name(&last_capacity);
+                if (r >= 0)
                         before_timestamp = now(CLOCK_BOOTTIME);
-                else if (r == -ENOENT)
+                else if (r == -ENOENT)
                         /* In case of no battery, system suspend interval will be set to HibernateDelaySec=. */
                         log_debug_errno(r, "Suspend Interval value set to %s: %m", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
                 else
                         return log_error_errno(r, "Error fetching battery capacity percentage: %m");
 
-                r = get_battery_discharge_rate();
+                r = get_total_suspend_interval(last_capacity, &total_suspend_interval);
                 if (r < 0)
-                        log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to get discharge rate, ignoring: %m");
-                else if (last_capacity * 2 <= r) {
-                        /* System should hibernate in case discharge rate is higher than double of battery current capacity
-                         * why double : Because while calculating suspend interval, we have taken a buffer of 30 minute and
-                         * discharge_rate is calculated on per 60 minute basis which is double. Also suspend_interval > 0 */
-                        log_debug("Current battery percentage capacity too low to suspend, so invoking hibernation");
-                        break;
-                } else {
-                        previous_discharge_rate = r;
-                        assert(previous_discharge_rate != 0);
-                        suspend_interval = usec_sub_unsigned(last_capacity * USEC_PER_HOUR / previous_discharge_rate, 30 * USEC_PER_MINUTE);
-                        /* The previous discharge rate is stored in per hour basis so converted to minutes.
-                         * Subtracted 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
-                }
+                        log_debug_errno(r, "Failed to estimate suspend interval using previous discharge rate, ignoring: %m");
+                else
+                        suspend_interval = total_suspend_interval;
+
                 log_debug("Set timerfd wake alarm for %s", FORMAT_TIMESPAN(suspend_interval, USEC_PER_SEC));
                 /* Wake alarm for system with or without battery to hibernate or estimate discharge rate whichever is applicable */
                 timespec_store(&ts.it_value, suspend_interval);
@@ -323,28 +311,26 @@ static int execute_s2h(const SleepConfig *sleep_config) {
                 /* Store fd_wait status */
                 woken_by_timer = FLAGS_SET(r, POLLIN);
 
-                r = read_battery_capacity_percentage();
-                if (r >= 0) {
-                        current_capacity = r;
-                        log_debug("Current battery charge percentage after wakeup: %d%%", current_capacity);
-                } else if (r == -ENOENT) {
-                        /* In case of no battery, system will be hibernated after 1st cycle of suspend */
+                r = fetch_batteries_capacity_by_name(&current_capacity);
+                if (r < 0) {
+                        /* In case of no battery or error while getting charge level, no need to measure
+                         * discharge rate. Instead system should wakeup if it is manual wakeup or
+                         * hibernate if this is a timer wakeup.   */
                         log_debug_errno(r, "Battery capacity percentage unavailable, cannot estimate discharge rate: %m");
+                        if (!woken_by_timer)
+                                return 0;
                         break;
-                } else
-                        return log_error_errno(r, "Error fetching battery capacity percentage: %m");
+                }
 
-                if (current_capacity >= last_capacity)
-                        log_debug("Battery was not discharged during suspension");
-                else {
-                        after_timestamp = now(CLOCK_BOOTTIME);
-                        log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
+                after_timestamp = now(CLOCK_BOOTTIME);
+                log_debug("Attempting to estimate battery discharge rate after wakeup from %s sleep", FORMAT_TIMESPAN(after_timestamp - before_timestamp, USEC_PER_HOUR));
 
-                        estimated_discharge_rate = (last_capacity - current_capacity) * USEC_PER_HOUR / (after_timestamp - before_timestamp);
-                        r = put_battery_discharge_rate(estimated_discharge_rate);
+                if (after_timestamp != before_timestamp) {
+                        r = estimate_battery_discharge_rate_per_hour(last_capacity, current_capacity, before_timestamp, after_timestamp);
                         if (r < 0)
-                                log_warning_errno(r, "Failed to update battery discharge rate, ignoring: %m");
-                }
+                                log_warning_errno(r, "Failed to estimate and update battery discharge rate, ignoring: %m");
+                } else
+                        log_debug("System woke up too early to estimate discharge rate");
 
                 if (!woken_by_timer)
                         /* Return as manual wakeup done. This also will return in case battery was charged during suspension */
index 148e8acd73e1c5a968e2f6a15282171ba467da8a..5648dfd83baaa321914f5a201150c7e241a966b2 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "sd-bus.h"
 
+#include "bus-locator.h"
 #include "bus-util.h"
 #include "bus-error.h"
 #include "def.h"
@@ -24,21 +25,16 @@ static int reload_manager(sd_bus *bus) {
 
         log_info("Reloading system manager configuration");
 
-        r = sd_bus_message_new_method_call(
+        r = bus_message_new_method_call(
                         bus,
                         &m,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
+                        bus_systemd_mgr,
                         "Reload");
         if (r < 0)
                 return bus_log_create_error(r);
 
-        /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
-         * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
-         * their timeout, and for everything else there's the same time budget in place. */
-
-        r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+        /* Reloading the daemon may take long, hence set a longer timeout here */
+        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
 
@@ -52,14 +48,13 @@ static int start_default_target(sd_bus *bus) {
         log_info("Starting "SPECIAL_DEFAULT_TARGET);
 
         /* Start this unit only if we can replace basic.target with it */
-        r = sd_bus_call_method(bus,
-                               "org.freedesktop.systemd1",
-                               "/org/freedesktop/systemd1",
-                               "org.freedesktop.systemd1.Manager",
-                               "StartUnit",
-                               &error,
-                               NULL,
-                               "ss", SPECIAL_DEFAULT_TARGET, "isolate");
+        r = bus_call_method(
+                        bus,
+                        bus_systemd_mgr,
+                        "StartUnit",
+                        &error,
+                        NULL,
+                        "ss", SPECIAL_DEFAULT_TARGET, "isolate");
 
         if (r < 0)
                 return log_error_errno(r, "Failed to start "SPECIAL_DEFAULT_TARGET": %s", bus_error_message(&error, r));
index de0e03ec95b0437d7607c8251b1b0e0109d2a190..5de5d81655f1a435e528f0d7734498273cca210b 100644 (file)
@@ -56,18 +56,7 @@ static bool test_prefix(const char *p) {
         if (strv_isempty(arg_prefixes))
                 return true;
 
-        STRV_FOREACH(i, arg_prefixes) {
-                const char *t;
-
-                t = path_startswith(*i, "/proc/sys/");
-                if (!t)
-                        t = *i;
-
-                if (path_startswith(p, t))
-                        return true;
-        }
-
-        return false;
+        return path_startswith_strv(p, arg_prefixes);
 }
 
 static Option *option_new(
@@ -97,7 +86,7 @@ static Option *option_new(
         return TAKE_PTR(o);
 }
 
-static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_failure) {
+static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_failure, bool ignore_enoent) {
         int r;
 
         r = sysctl_write(key, value);
@@ -111,7 +100,7 @@ static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_
                  * In all other cases log an error and make the tool fail. */
                 if (ignore_failure || (!arg_strict && (r == -EROFS || ERRNO_IS_PRIVILEGE(r))))
                         log_debug_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
-                else if (!arg_strict && r == -ENOENT)
+                else if (ignore_enoent && r == -ENOENT)
                         log_warning_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
                 else
                         return log_error_errno(r, "Couldn't write '%s' to '%s': %m", value, key);
@@ -120,63 +109,113 @@ static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_
         return 0;
 }
 
-static int apply_all(OrderedHashmap *sysctl_options) {
-        Option *option;
-        int r = 0;
+static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, Option *option, const char *prefix) {
+        _cleanup_strv_free_ char **paths = NULL;
+        _cleanup_free_ char *pattern = NULL;
+        int r, k;
 
-        ORDERED_HASHMAP_FOREACH(option, sysctl_options) {
-                int k;
+        assert(sysctl_options);
+        assert(option);
 
-                /* Ignore "negative match" options, they are there only to exclude stuff from globs. */
-                if (!option->value)
+        if (prefix) {
+                _cleanup_free_ char *key = NULL;
+
+                r = path_glob_can_match(option->key, prefix, &key);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to check if the glob '%s' matches prefix '%s': %m",
+                                               option->key, prefix);
+                if (r == 0) {
+                        log_debug("The glob '%s' does not match prefix '%s'.", option->key, prefix);
+                        return 0;
+                }
+
+                log_debug("The glob '%s' is prefixed with '%s': '%s'", option->key, prefix, key);
+
+                if (!string_is_glob(key)) {
+                        /* The prefixed pattern is not glob anymore. Let's skip to call glob(). */
+                        if (ordered_hashmap_contains(sysctl_options, key)) {
+                                log_debug("Not setting %s (explicit setting exists).", key);
+                                return 0;
+                        }
+
+                        return sysctl_write_or_warn(key, option->value,
+                                                    /* ignore_failure = */ option->ignore_failure,
+                                                    /* ignore_enoent = */ true);
+                }
+
+                pattern = path_join("/proc/sys", key);
+        } else
+                pattern = path_join("/proc/sys", option->key);
+        if (!pattern)
+                return log_oom();
+
+        r = glob_extend(&paths, pattern, GLOB_NOCHECK);
+        if (r < 0) {
+                if (r == -ENOENT) {
+                        log_debug("No match for glob: %s", option->key);
+                        return 0;
+                }
+                if (option->ignore_failure || ERRNO_IS_PRIVILEGE(r)) {
+                        log_debug_errno(r, "Failed to resolve glob '%s', ignoring: %m", option->key);
+                        return 0;
+                } else
+                        return log_error_errno(r, "Couldn't resolve glob '%s': %m", option->key);
+        }
+
+        STRV_FOREACH(s, paths) {
+                const char *key;
+
+                assert_se(key = path_startswith(*s, "/proc/sys"));
+
+                if (ordered_hashmap_contains(sysctl_options, key)) {
+                        log_debug("Not setting %s (explicit setting exists).", key);
                         continue;
+                }
 
-                if (string_is_glob(option->key)) {
-                        _cleanup_strv_free_ char **paths = NULL;
-                        _cleanup_free_ char *pattern = NULL;
+                k = sysctl_write_or_warn(key, option->value,
+                                         /* ignore_failure = */ option->ignore_failure,
+                                         /* ignore_enoent = */ !arg_strict);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
 
-                        pattern = path_join("/proc/sys", option->key);
-                        if (!pattern)
-                                return log_oom();
+        return r;
+}
 
-                        k = glob_extend(&paths, pattern, GLOB_NOCHECK);
-                        if (k < 0) {
-                                if (option->ignore_failure || ERRNO_IS_PRIVILEGE(k))
-                                        log_debug_errno(k, "Failed to resolve glob '%s', ignoring: %m",
-                                                        option->key);
-                                else {
-                                        log_error_errno(k, "Couldn't resolve glob '%s': %m",
-                                                        option->key);
-                                        if (r == 0)
-                                                r = k;
-                                }
+static int apply_glob_option(OrderedHashmap *sysctl_options, Option *option) {
+        int r = 0, k;
 
-                        } else if (strv_isempty(paths))
-                                log_debug("No match for glob: %s", option->key);
+        if (strv_isempty(arg_prefixes))
+                return apply_glob_option_with_prefix(sysctl_options, option, NULL);
 
-                        STRV_FOREACH(s, paths) {
-                                const char *key;
+        STRV_FOREACH(i, arg_prefixes) {
+                k = apply_glob_option_with_prefix(sysctl_options, option, *i);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
 
-                                assert_se(key = path_startswith(*s, "/proc/sys"));
+        return r;
+}
 
-                                if (!test_prefix(key))
-                                        continue;
+static int apply_all(OrderedHashmap *sysctl_options) {
+        Option *option;
+        int r = 0;
 
-                                if (ordered_hashmap_contains(sysctl_options, key)) {
-                                        log_debug("Not setting %s (explicit setting exists).", key);
-                                        continue;
-                                }
+        ORDERED_HASHMAP_FOREACH(option, sysctl_options) {
+                int k;
 
-                                k = sysctl_write_or_warn(key, option->value, option->ignore_failure);
-                                if (r == 0)
-                                        r = k;
-                        }
+                /* Ignore "negative match" options, they are there only to exclude stuff from globs. */
+                if (!option->value)
+                        continue;
 
-                } else {
-                        k = sysctl_write_or_warn(option->key, option->value, option->ignore_failure);
-                        if (r == 0)
-                                r = k;
-                }
+                if (string_is_glob(option->key))
+                        k = apply_glob_option(sysctl_options, option);
+                else
+                        k = sysctl_write_or_warn(option->key, option->value,
+                                                 /* ignore_failure = */ option->ignore_failure,
+                                                 /* ignore_enoent = */ !arg_strict);
+                if (k < 0 && r >= 0)
+                        r = k;
         }
 
         return r;
@@ -254,9 +293,6 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                     !test_prefix(p))
                         continue;
 
-                if (ordered_hashmap_ensure_allocated(sysctl_options, &option_hash_ops) < 0)
-                        return log_oom();
-
                 existing = ordered_hashmap_get(*sysctl_options, p);
                 if (existing) {
                         if (streq_ptr(value, existing->value)) {
@@ -272,7 +308,7 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                 if (!new_option)
                         return log_oom();
 
-                k = ordered_hashmap_put(*sysctl_options, new_option->key, new_option);
+                k = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, new_option->key, new_option);
                 if (k < 0)
                         return log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", p);
 
@@ -363,6 +399,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_PREFIX: {
+                        const char *s;
                         char *p;
 
                         /* We used to require people to specify absolute paths
@@ -371,10 +408,8 @@ static int parse_argv(int argc, char *argv[]) {
                          * sysctl name available. */
                         sysctl_normalize(optarg);
 
-                        if (path_startswith(optarg, "/proc/sys"))
-                                p = strdup(optarg);
-                        else
-                                p = path_join("/proc/sys", optarg);
+                        s = path_startswith(optarg, "/proc/sys");
+                        p = strdup(s ?: optarg);
                         if (!p)
                                 return log_oom();
 
index 33de7d161e2ea7c09afcfeaf85d155e2afd8f91b..4f025ac4d2e757ff94628503be275538f309d921 100644 (file)
@@ -37,12 +37,8 @@ int daemon_reload(enum action action, bool graceful) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are
-         * rerun which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the
-         * generators can have their timeout, and for everything else there's the same time budget in
-         * place. */
-
-        r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+        /* Reloading the daemon may take long, hence set a longer timeout here */
+        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
 
         /* On reexecution, we expect a disconnect, not a reply */
         if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && action == ACTION_REEXEC)
index 0b2f8f8b4292d8ccbfc8ae4e0dced6549871e563..41d3f832913c0118a57c0144ce6ecb5a1d1177e5 100644 (file)
@@ -144,6 +144,8 @@ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event);
 int sd_device_monitor_detach_event(sd_device_monitor *m);
 sd_event *sd_device_monitor_get_event(sd_device_monitor *m);
 sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m);
+int sd_device_monitor_set_description(sd_device_monitor *m, const char *description);
+int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret);
 int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata);
 int sd_device_monitor_stop(sd_device_monitor *m);
 
index 855f938b091f4a4a74fd9392fdc904a7716a16ad..6a863794a4c65c2eb97b1aa1ad0326c5a5acd5b4 100644 (file)
@@ -247,7 +247,7 @@ int sd_dhcp_client_set_ifname(
 int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret);
 int sd_dhcp_client_set_mac(
                 sd_dhcp_client *client,
-                const uint8_t *addr,
+                const uint8_t *hw_addr,
                 const uint8_t *bcast_addr,
                 size_t addr_len,
                 uint16_t arp_type);
index bafaa065f00cce36c80388690420d317608ce5b7..ffb9ba473956a27ffa36b4c5e553527fcd97fe8d 100644 (file)
@@ -25,191 +25,169 @@ _SD_BEGIN_DECLARATIONS;
 
 /* Hey! If you add a new message here, you *must* also update the message catalog with an appropriate explanation */
 
-/* And if you add a new ID here, make sure to generate a random one with "systemd-id128 new". Do not use any other IDs,
- * and do not count them up manually. */
-
-#define SD_MESSAGE_JOURNAL_START          SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
-#define SD_MESSAGE_JOURNAL_START_STR      SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
-#define SD_MESSAGE_JOURNAL_STOP           SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
-#define SD_MESSAGE_JOURNAL_STOP_STR       SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
-#define SD_MESSAGE_JOURNAL_DROPPED        SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
-#define SD_MESSAGE_JOURNAL_DROPPED_STR    SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
-#define SD_MESSAGE_JOURNAL_MISSED         SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
-#define SD_MESSAGE_JOURNAL_MISSED_STR     SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
-#define SD_MESSAGE_JOURNAL_USAGE          SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
-#define SD_MESSAGE_JOURNAL_USAGE_STR      SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
-
-#define SD_MESSAGE_COREDUMP               SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
-#define SD_MESSAGE_COREDUMP_STR           SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
-#define SD_MESSAGE_TRUNCATED_CORE         SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
-#define SD_MESSAGE_TRUNCATED_CORE_STR     SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
-#define SD_MESSAGE_BACKTRACE              SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
-#define SD_MESSAGE_BACKTRACE_STR          SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
-
-#define SD_MESSAGE_SESSION_START          SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
-#define SD_MESSAGE_SESSION_START_STR      SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
-#define SD_MESSAGE_SESSION_STOP           SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
-#define SD_MESSAGE_SESSION_STOP_STR       SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
-#define SD_MESSAGE_SEAT_START             SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
-#define SD_MESSAGE_SEAT_START_STR         SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
-#define SD_MESSAGE_SEAT_STOP              SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
-#define SD_MESSAGE_SEAT_STOP_STR          SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
-#define SD_MESSAGE_MACHINE_START          SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
-#define SD_MESSAGE_MACHINE_START_STR      SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
-#define SD_MESSAGE_MACHINE_STOP           SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
-#define SD_MESSAGE_MACHINE_STOP_STR       SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
-
-#define SD_MESSAGE_TIME_CHANGE            SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
-#define SD_MESSAGE_TIME_CHANGE_STR        SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
-#define SD_MESSAGE_TIMEZONE_CHANGE        SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
-#define SD_MESSAGE_TIMEZONE_CHANGE_STR    SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
-
-#define SD_MESSAGE_TAINTED                SD_ID128_MAKE(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
-#define SD_MESSAGE_TAINTED_STR            SD_ID128_MAKE_STR(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
-#define SD_MESSAGE_STARTUP_FINISHED       SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
-#define SD_MESSAGE_STARTUP_FINISHED_STR   SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
-#define SD_MESSAGE_USER_STARTUP_FINISHED \
-                                          SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
-#define SD_MESSAGE_USER_STARTUP_FINISHED_STR \
-                                          SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
-
-#define SD_MESSAGE_SLEEP_START            SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
-#define SD_MESSAGE_SLEEP_START_STR        SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
-#define SD_MESSAGE_SLEEP_STOP             SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
-#define SD_MESSAGE_SLEEP_STOP_STR         SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
-
-#define SD_MESSAGE_SHUTDOWN               SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
-#define SD_MESSAGE_SHUTDOWN_STR           SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
-
-#define SD_MESSAGE_FACTORY_RESET          SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
-#define SD_MESSAGE_FACTORY_RESET_STR      SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
-
-/* The messages below are actually about jobs, not really about units, the macros are misleadingly named. Moreover
- * SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job either finishes with
- * SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
-#define SD_MESSAGE_UNIT_STARTING          SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
-#define SD_MESSAGE_UNIT_STARTING_STR      SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
-#define SD_MESSAGE_UNIT_STARTED           SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
-#define SD_MESSAGE_UNIT_STARTED_STR       SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
-#define SD_MESSAGE_UNIT_FAILED            SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
-#define SD_MESSAGE_UNIT_FAILED_STR        SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
-#define SD_MESSAGE_UNIT_STOPPING          SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
-#define SD_MESSAGE_UNIT_STOPPING_STR      SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
-#define SD_MESSAGE_UNIT_STOPPED           SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
-#define SD_MESSAGE_UNIT_STOPPED_STR       SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
-#define SD_MESSAGE_UNIT_RELOADING         SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
-#define SD_MESSAGE_UNIT_RELOADING_STR     SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
-#define SD_MESSAGE_UNIT_RELOADED          SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
-#define SD_MESSAGE_UNIT_RELOADED_STR      SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
-
-#define SD_MESSAGE_UNIT_RESTART_SCHEDULED SD_ID128_MAKE(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
-#define SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR                   \
-                                          SD_ID128_MAKE_STR(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
-
-#define SD_MESSAGE_UNIT_RESOURCES         SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
-#define SD_MESSAGE_UNIT_RESOURCES_STR     SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
-
-#define SD_MESSAGE_UNIT_SUCCESS           SD_ID128_MAKE(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
-#define SD_MESSAGE_UNIT_SUCCESS_STR       SD_ID128_MAKE_STR(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
-#define SD_MESSAGE_UNIT_SKIPPED           SD_ID128_MAKE(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
-#define SD_MESSAGE_UNIT_SKIPPED_STR       SD_ID128_MAKE_STR(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
-#define SD_MESSAGE_UNIT_FAILURE_RESULT    SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
-#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR \
-                                          SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
-
-#define SD_MESSAGE_SPAWN_FAILED           SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
-#define SD_MESSAGE_SPAWN_FAILED_STR       SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
-
-#define SD_MESSAGE_UNIT_PROCESS_EXIT      SD_ID128_MAKE(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
-#define SD_MESSAGE_UNIT_PROCESS_EXIT_STR  SD_ID128_MAKE_STR(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
-
-#define SD_MESSAGE_FORWARD_SYSLOG_MISSED  SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
-#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR \
-                                          SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
-
-#define SD_MESSAGE_OVERMOUNTING           SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
-#define SD_MESSAGE_OVERMOUNTING_STR       SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
-
-#define SD_MESSAGE_UNIT_OOMD_KILL         SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
-#define SD_MESSAGE_UNIT_OOMD_KILL_STR     SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
-
-#define SD_MESSAGE_UNIT_OUT_OF_MEMORY     SD_ID128_MAKE(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
-#define SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR SD_ID128_MAKE_STR(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
-
-#define SD_MESSAGE_LID_OPENED             SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
-#define SD_MESSAGE_LID_OPENED_STR         SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
-#define SD_MESSAGE_LID_CLOSED             SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
-#define SD_MESSAGE_LID_CLOSED_STR         SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
-#define SD_MESSAGE_SYSTEM_DOCKED          SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
-#define SD_MESSAGE_SYSTEM_DOCKED_STR      SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
-#define SD_MESSAGE_SYSTEM_UNDOCKED        SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
-#define SD_MESSAGE_SYSTEM_UNDOCKED_STR    SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
-#define SD_MESSAGE_POWER_KEY              SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
-#define SD_MESSAGE_POWER_KEY_STR          SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
-#define SD_MESSAGE_POWER_KEY_LONG_PRESS   SD_ID128_MAKE(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
-#define SD_MESSAGE_POWER_KEY_LONG_PRESS_STR \
-                                          SD_ID128_MAKE_STR(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
-#define SD_MESSAGE_REBOOT_KEY             SD_ID128_MAKE(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
-#define SD_MESSAGE_REBOOT_KEY_STR         SD_ID128_MAKE_STR(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
-#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS  SD_ID128_MAKE(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
-#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR \
-                                          SD_ID128_MAKE_STR(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
-#define SD_MESSAGE_SUSPEND_KEY            SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
-#define SD_MESSAGE_SUSPEND_KEY_STR        SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
-#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS SD_ID128_MAKE(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
-#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR \
-                                          SD_ID128_MAKE_STR(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
-#define SD_MESSAGE_HIBERNATE_KEY          SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
-#define SD_MESSAGE_HIBERNATE_KEY_STR      SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
-#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS \
-                                          SD_ID128_MAKE(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
-#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR \
-                                          SD_ID128_MAKE_STR(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
-
-#define SD_MESSAGE_INVALID_CONFIGURATION  SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
-#define SD_MESSAGE_INVALID_CONFIGURATION_STR \
-                                          SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
-
-#define SD_MESSAGE_DNSSEC_FAILURE         SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
-#define SD_MESSAGE_DNSSEC_FAILURE_STR     SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
-#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED \
-                                          SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
-#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR \
-                                          SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
-#define SD_MESSAGE_DNSSEC_DOWNGRADE       SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
-#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR   SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
-
-#define SD_MESSAGE_UNSAFE_USER_NAME       SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
-#define SD_MESSAGE_UNSAFE_USER_NAME_STR   SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
-
-#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE \
-                                          SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
-#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR \
-                                          SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
-#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE \
-                                          SD_ID128_MAKE(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
-#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR \
-                                          SD_ID128_MAKE_STR(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
-
-#define SD_MESSAGE_NOBODY_USER_UNSUITABLE SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
-#define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR \
-                                          SD_ID128_MAKE_STR(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
-
-#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED \
-                                          SD_ID128_MAKE(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
-#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED_STR \
-                                          SD_ID128_MAKE_STR(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
-
-#define SD_MESSAGE_TIME_SYNC              SD_ID128_MAKE(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
-#define SD_MESSAGE_TIME_SYNC_STR          SD_ID128_MAKE_STR(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
-
-#define SD_MESSAGE_LOGIND_SHUTDOWN        SD_ID128_MAKE(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
-#define SD_MESSAGE_LOGIND_SHUTDOWN_STR    SD_ID128_MAKE_STR(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
-
-#define SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED \
-                                          SD_ID128_MAKE(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
-#define SD_MESSAGE_LOGIND_SHUTDOWN_CANCELED_STR \
-                                          SD_ID128_MAKE_STR(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
+/* And if you add a new ID here, make sure to generate a random one with "systemd-id128 new". Do not use any
+ * other IDs, and do not count them up manually. */
+
+#define SD_MESSAGE_JOURNAL_START                      SD_ID128_MAKE(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
+#define SD_MESSAGE_JOURNAL_START_STR                  SD_ID128_MAKE_STR(f7,73,79,a8,49,0b,40,8b,be,5f,69,40,50,5a,77,7b)
+#define SD_MESSAGE_JOURNAL_STOP                       SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
+#define SD_MESSAGE_JOURNAL_STOP_STR                   SD_ID128_MAKE_STR(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b)
+#define SD_MESSAGE_JOURNAL_DROPPED                    SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
+#define SD_MESSAGE_JOURNAL_DROPPED_STR                SD_ID128_MAKE_STR(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e)
+#define SD_MESSAGE_JOURNAL_MISSED                     SD_ID128_MAKE(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
+#define SD_MESSAGE_JOURNAL_MISSED_STR                 SD_ID128_MAKE_STR(e9,bf,28,e6,e8,34,48,1b,b6,f4,8f,54,8a,d1,36,06)
+#define SD_MESSAGE_JOURNAL_USAGE                      SD_ID128_MAKE(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
+#define SD_MESSAGE_JOURNAL_USAGE_STR                  SD_ID128_MAKE_STR(ec,38,7f,57,7b,84,4b,8f,a9,48,f3,3c,ad,9a,75,e6)
+
+#define SD_MESSAGE_COREDUMP                           SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
+#define SD_MESSAGE_COREDUMP_STR                       SD_ID128_MAKE_STR(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1)
+#define SD_MESSAGE_TRUNCATED_CORE                     SD_ID128_MAKE(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
+#define SD_MESSAGE_TRUNCATED_CORE_STR                 SD_ID128_MAKE_STR(5a,ad,d8,e9,54,dc,4b,1a,8c,95,4d,63,fd,9e,11,37)
+#define SD_MESSAGE_BACKTRACE                          SD_ID128_MAKE(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
+#define SD_MESSAGE_BACKTRACE_STR                      SD_ID128_MAKE_STR(1f,4e,0a,44,a8,86,49,93,9a,ae,a3,4f,c6,da,8c,95)
+
+#define SD_MESSAGE_SESSION_START                      SD_ID128_MAKE(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
+#define SD_MESSAGE_SESSION_START_STR                  SD_ID128_MAKE_STR(8d,45,62,0c,1a,43,48,db,b1,74,10,da,57,c6,0c,66)
+#define SD_MESSAGE_SESSION_STOP                       SD_ID128_MAKE(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
+#define SD_MESSAGE_SESSION_STOP_STR                   SD_ID128_MAKE_STR(33,54,93,94,24,b4,45,6d,98,02,ca,83,33,ed,42,4a)
+#define SD_MESSAGE_SEAT_START                         SD_ID128_MAKE(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
+#define SD_MESSAGE_SEAT_START_STR                     SD_ID128_MAKE_STR(fc,be,fc,5d,a2,3d,42,80,93,f9,7c,82,a9,29,0f,7b)
+#define SD_MESSAGE_SEAT_STOP                          SD_ID128_MAKE(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
+#define SD_MESSAGE_SEAT_STOP_STR                      SD_ID128_MAKE_STR(e7,85,2b,fe,46,78,4e,d0,ac,cd,e0,4b,c8,64,c2,d5)
+#define SD_MESSAGE_MACHINE_START                      SD_ID128_MAKE(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
+#define SD_MESSAGE_MACHINE_START_STR                  SD_ID128_MAKE_STR(24,d8,d4,45,25,73,40,24,96,06,83,81,a6,31,2d,f2)
+#define SD_MESSAGE_MACHINE_STOP                       SD_ID128_MAKE(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
+#define SD_MESSAGE_MACHINE_STOP_STR                   SD_ID128_MAKE_STR(58,43,2b,d3,ba,ce,47,7c,b5,14,b5,63,81,b8,a7,58)
+
+#define SD_MESSAGE_TIME_CHANGE                        SD_ID128_MAKE(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
+#define SD_MESSAGE_TIME_CHANGE_STR                    SD_ID128_MAKE_STR(c7,a7,87,07,9b,35,4e,aa,a9,e7,7b,37,18,93,cd,27)
+#define SD_MESSAGE_TIMEZONE_CHANGE                    SD_ID128_MAKE(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
+#define SD_MESSAGE_TIMEZONE_CHANGE_STR                SD_ID128_MAKE_STR(45,f8,2f,4a,ef,7a,4b,bf,94,2c,e8,61,d1,f2,09,90)
+
+#define SD_MESSAGE_TAINTED                            SD_ID128_MAKE(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
+#define SD_MESSAGE_TAINTED_STR                        SD_ID128_MAKE_STR(50,87,6a,9d,b0,0f,4c,40,bd,e1,a2,ad,38,1c,3a,1b)
+#define SD_MESSAGE_STARTUP_FINISHED                   SD_ID128_MAKE(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
+#define SD_MESSAGE_STARTUP_FINISHED_STR               SD_ID128_MAKE_STR(b0,7a,24,9c,d0,24,41,4a,82,dd,00,cd,18,13,78,ff)
+#define SD_MESSAGE_USER_STARTUP_FINISHED              SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
+#define SD_MESSAGE_USER_STARTUP_FINISHED_STR          SD_ID128_MAKE_STR(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1)
+
+#define SD_MESSAGE_SLEEP_START                        SD_ID128_MAKE(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
+#define SD_MESSAGE_SLEEP_START_STR                    SD_ID128_MAKE_STR(6b,bd,95,ee,97,79,41,e4,97,c4,8b,e2,7c,25,41,28)
+#define SD_MESSAGE_SLEEP_STOP                         SD_ID128_MAKE(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
+#define SD_MESSAGE_SLEEP_STOP_STR                     SD_ID128_MAKE_STR(88,11,e6,df,2a,8e,40,f5,8a,94,ce,a2,6f,8e,bf,14)
+
+#define SD_MESSAGE_SHUTDOWN                           SD_ID128_MAKE(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
+#define SD_MESSAGE_SHUTDOWN_STR                       SD_ID128_MAKE_STR(98,26,88,66,d1,d5,4a,49,9c,4e,98,92,1d,93,bc,40)
+
+#define SD_MESSAGE_FACTORY_RESET                      SD_ID128_MAKE(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+#define SD_MESSAGE_FACTORY_RESET_STR                  SD_ID128_MAKE_STR(c1,4a,af,76,ec,28,4a,5f,a1,f1,05,f8,8d,fb,06,1c)
+
+/* The messages below are actually about jobs, not really about units, the macros are misleadingly named.
+ * Moreover SD_MESSAGE_UNIT_FAILED is not actually about a failing unit but about a failed start job. A job
+ * either finishes with SD_MESSAGE_UNIT_STARTED or with SD_MESSAGE_UNIT_FAILED hence. */
+#define SD_MESSAGE_UNIT_STARTING                      SD_ID128_MAKE(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
+#define SD_MESSAGE_UNIT_STARTING_STR                  SD_ID128_MAKE_STR(7d,49,58,e8,42,da,4a,75,8f,6c,1c,dc,7b,36,dc,c5)
+#define SD_MESSAGE_UNIT_STARTED                       SD_ID128_MAKE(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
+#define SD_MESSAGE_UNIT_STARTED_STR                   SD_ID128_MAKE_STR(39,f5,34,79,d3,a0,45,ac,8e,11,78,62,48,23,1f,bf)
+#define SD_MESSAGE_UNIT_FAILED                        SD_ID128_MAKE(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
+#define SD_MESSAGE_UNIT_FAILED_STR                    SD_ID128_MAKE_STR(be,02,cf,68,55,d2,42,8b,a4,0d,f7,e9,d0,22,f0,3d)
+#define SD_MESSAGE_UNIT_STOPPING                      SD_ID128_MAKE(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
+#define SD_MESSAGE_UNIT_STOPPING_STR                  SD_ID128_MAKE_STR(de,5b,42,6a,63,be,47,a7,b6,ac,3e,aa,c8,2e,2f,6f)
+#define SD_MESSAGE_UNIT_STOPPED                       SD_ID128_MAKE(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
+#define SD_MESSAGE_UNIT_STOPPED_STR                   SD_ID128_MAKE_STR(9d,1a,aa,27,d6,01,40,bd,96,36,54,38,aa,d2,02,86)
+#define SD_MESSAGE_UNIT_RELOADING                     SD_ID128_MAKE(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
+#define SD_MESSAGE_UNIT_RELOADING_STR                 SD_ID128_MAKE_STR(d3,4d,03,7f,ff,18,47,e6,ae,66,9a,37,0e,69,47,25)
+#define SD_MESSAGE_UNIT_RELOADED                      SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
+#define SD_MESSAGE_UNIT_RELOADED_STR                  SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
+
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED             SD_ID128_MAKE(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR         SD_ID128_MAKE_STR(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+
+#define SD_MESSAGE_UNIT_RESOURCES                     SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+#define SD_MESSAGE_UNIT_RESOURCES_STR                 SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+
+#define SD_MESSAGE_UNIT_SUCCESS                       SD_ID128_MAKE(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
+#define SD_MESSAGE_UNIT_SUCCESS_STR                   SD_ID128_MAKE_STR(7a,d2,d1,89,f7,e9,4e,70,a3,8c,78,13,54,91,24,48)
+#define SD_MESSAGE_UNIT_SKIPPED                       SD_ID128_MAKE(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
+#define SD_MESSAGE_UNIT_SKIPPED_STR                   SD_ID128_MAKE_STR(0e,42,84,a0,ca,ca,4b,fc,81,c0,bb,67,86,97,26,73)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT                SD_ID128_MAKE(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+#define SD_MESSAGE_UNIT_FAILURE_RESULT_STR            SD_ID128_MAKE_STR(d9,b3,73,ed,55,a6,4f,eb,82,42,e0,2d,be,79,a4,9c)
+
+#define SD_MESSAGE_SPAWN_FAILED                       SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
+#define SD_MESSAGE_SPAWN_FAILED_STR                   SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
+
+#define SD_MESSAGE_UNIT_PROCESS_EXIT                  SD_ID128_MAKE(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
+#define SD_MESSAGE_UNIT_PROCESS_EXIT_STR              SD_ID128_MAKE_STR(98,e3,22,20,3f,7a,4e,d2,90,d0,9f,e0,3c,09,fe,15)
+
+#define SD_MESSAGE_FORWARD_SYSLOG_MISSED              SD_ID128_MAKE(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
+#define SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR          SD_ID128_MAKE_STR(00,27,22,9c,a0,64,41,81,a7,6c,4e,92,45,8a,fa,2e)
+
+#define SD_MESSAGE_OVERMOUNTING                       SD_ID128_MAKE(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
+#define SD_MESSAGE_OVERMOUNTING_STR                   SD_ID128_MAKE_STR(1d,ee,03,69,c7,fc,47,36,b7,09,9b,38,ec,b4,6e,e7)
+
+#define SD_MESSAGE_UNIT_OOMD_KILL                     SD_ID128_MAKE(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+#define SD_MESSAGE_UNIT_OOMD_KILL_STR                 SD_ID128_MAKE_STR(d9,89,61,1b,15,e4,4c,9d,bf,31,e3,c8,12,56,e4,ed)
+
+#define SD_MESSAGE_UNIT_OUT_OF_MEMORY                 SD_ID128_MAKE(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
+#define SD_MESSAGE_UNIT_OUT_OF_MEMORY_STR             SD_ID128_MAKE_STR(fe,6f,aa,94,e7,77,46,63,a0,da,52,71,78,91,d8,ef)
+
+#define SD_MESSAGE_LID_OPENED                         SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
+#define SD_MESSAGE_LID_OPENED_STR                     SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,6f)
+#define SD_MESSAGE_LID_CLOSED                         SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
+#define SD_MESSAGE_LID_CLOSED_STR                     SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,70)
+#define SD_MESSAGE_SYSTEM_DOCKED                      SD_ID128_MAKE(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
+#define SD_MESSAGE_SYSTEM_DOCKED_STR                  SD_ID128_MAKE_STR(f5,f4,16,b8,62,07,4b,28,92,7a,48,c3,ba,7d,51,ff)
+#define SD_MESSAGE_SYSTEM_UNDOCKED                    SD_ID128_MAKE(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
+#define SD_MESSAGE_SYSTEM_UNDOCKED_STR                SD_ID128_MAKE_STR(51,e1,71,bd,58,52,48,56,81,10,14,4c,51,7c,ca,53)
+#define SD_MESSAGE_POWER_KEY                          SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
+#define SD_MESSAGE_POWER_KEY_STR                      SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,71)
+#define SD_MESSAGE_POWER_KEY_LONG_PRESS               SD_ID128_MAKE(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
+#define SD_MESSAGE_POWER_KEY_LONG_PRESS_STR           SD_ID128_MAKE_STR(3e,01,17,10,1e,b2,43,c1,b9,a5,0d,b3,49,4a,b1,0b)
+#define SD_MESSAGE_REBOOT_KEY                         SD_ID128_MAKE(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
+#define SD_MESSAGE_REBOOT_KEY_STR                     SD_ID128_MAKE_STR(9f,a9,d2,c0,12,13,4e,c3,85,45,1f,fe,31,6f,97,d0)
+#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS              SD_ID128_MAKE(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
+#define SD_MESSAGE_REBOOT_KEY_LONG_PRESS_STR          SD_ID128_MAKE_STR(f1,c5,9a,58,c9,d9,43,66,89,65,c3,37,ca,ec,59,75)
+#define SD_MESSAGE_SUSPEND_KEY                        SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
+#define SD_MESSAGE_SUSPEND_KEY_STR                    SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
+#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS             SD_ID128_MAKE(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
+#define SD_MESSAGE_SUSPEND_KEY_LONG_PRESS_STR         SD_ID128_MAKE_STR(bf,da,f6,d3,12,ab,40,07,bc,1f,e4,0a,15,df,78,e8)
+#define SD_MESSAGE_HIBERNATE_KEY                      SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
+#define SD_MESSAGE_HIBERNATE_KEY_STR                  SD_ID128_MAKE_STR(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
+#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS           SD_ID128_MAKE(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
+#define SD_MESSAGE_HIBERNATE_KEY_LONG_PRESS_STR       SD_ID128_MAKE_STR(16,78,36,df,6f,7f,42,8e,98,14,72,27,b2,dc,89,45)
+
+#define SD_MESSAGE_INVALID_CONFIGURATION              SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
+#define SD_MESSAGE_INVALID_CONFIGURATION_STR          SD_ID128_MAKE_STR(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
+
+#define SD_MESSAGE_DNSSEC_FAILURE                     SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
+#define SD_MESSAGE_DNSSEC_FAILURE_STR                 SD_ID128_MAKE_STR(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
+#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED        SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
+#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED_STR    SD_ID128_MAKE_STR(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
+#define SD_MESSAGE_DNSSEC_DOWNGRADE                   SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR               SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+
+#define SD_MESSAGE_UNSAFE_USER_NAME                   SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+#define SD_MESSAGE_UNSAFE_USER_NAME_STR               SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+
+#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE      SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
+#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR  SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
+#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE           SD_ID128_MAKE(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
+#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR       SD_ID128_MAKE_STR(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
+
+#define SD_MESSAGE_NOBODY_USER_UNSUITABLE             SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
+#define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR         SD_ID128_MAKE_STR(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
+
+#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED     SD_ID128_MAKE(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
+#define SD_MESSAGE_SYSTEMD_UDEV_SETTLE_DEPRECATED_STR SD_ID128_MAKE_STR(1c,04,54,c1,bd,22,41,e0,ac,6f,ef,b4,bc,63,14,33)
+
+#define SD_MESSAGE_TIME_SYNC                          SD_ID128_MAKE(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
+#define SD_MESSAGE_TIME_SYNC_STR                      SD_ID128_MAKE_STR(7c,8a,41,f3,7b,76,49,41,a0,e1,78,0b,1b,e2,f0,37)
+
+#define SD_MESSAGE_SHUTDOWN_SCHEDULED                 SD_ID128_MAKE(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
+#define SD_MESSAGE_SHUTDOWN_SCHEDULED_STR             SD_ID128_MAKE_STR(9e,70,66,27,9d,c8,40,3d,a7,9c,e4,b1,a6,90,64,b2)
+
+#define SD_MESSAGE_SHUTDOWN_CANCELED                  SD_ID128_MAKE(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
+#define SD_MESSAGE_SHUTDOWN_CANCELED_STR              SD_ID128_MAKE_STR(24,9f,6f,b9,e6,e2,42,8c,96,f3,f0,87,56,81,ff,a3)
 
 _SD_END_DECLARATIONS;
 
index aba08a7563b5823b6883c1380d200bbc669933bc..9c1abf984ecdf3886d063d08ed0b349c9469a1ec 100644 (file)
@@ -507,7 +507,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
                         break;
         }
 
-        r = fflush_and_check(passwd);
+        r = fflush_sync_and_check(passwd);
         if (r < 0)
                 return log_debug_errno(r, "Failed to flush %s: %m", passwd_tmp);
 
@@ -581,7 +581,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
 
         ORDERED_HASHMAP_FOREACH(i, todo_uids) {
                 _cleanup_(erase_and_freep) char *creds_password = NULL;
-                _cleanup_free_ char *cn = NULL;
+                bool is_hashed;
 
                 struct spwd n = {
                         .sp_namp = i->name,
@@ -595,30 +595,16 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
                         .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
                 };
 
-                /* Try to pick up the password for this account via the credentials logic */
-                cn = strjoin("passwd.hashed-password.", i->name);
-                if (!cn)
-                        return -ENOMEM;
-
-                r = read_credential(cn, (void**) &creds_password, NULL);
-                if (r == -ENOENT) {
-                        _cleanup_(erase_and_freep) char *plaintext_password = NULL;
-
-                        free(cn);
-                        cn = strjoin("passwd.plaintext-password.", i->name);
-                        if (!cn)
-                                return -ENOMEM;
+                r = get_credential_user_password(i->name, &creds_password, &is_hashed);
+                if (r < 0)
+                        log_debug_errno(r, "Couldn't read password credential for user '%s', ignoring: %m", i->name);
 
-                        r = read_credential(cn, (void**) &plaintext_password, NULL);
+                if (creds_password && !is_hashed) {
+                        _cleanup_(erase_and_freep) char* plaintext_password = TAKE_PTR(creds_password);
+                        r = hash_password(plaintext_password, &creds_password);
                         if (r < 0)
-                                log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
-                        else {
-                                r = hash_password(plaintext_password, &creds_password);
-                                if (r < 0)
-                                        return log_debug_errno(r, "Failed to hash password: %m");
-                        }
-                } else if (r < 0)
-                        log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+                                return log_debug_errno(r, "Failed to hash password: %m");
+                }
 
                 if (creds_password)
                         n.sp_pwdp = creds_password;
@@ -1169,7 +1155,7 @@ static int add_user(Item *i) {
         return 0;
 }
 
-static int gid_is_ok(gid_t gid) {
+static int gid_is_ok(gid_t gid, bool check_with_uid) {
         struct group *g;
         struct passwd *p;
 
@@ -1177,13 +1163,13 @@ static int gid_is_ok(gid_t gid) {
                 return 0;
 
         /* Avoid reusing gids that are already used by a different user */
-        if (ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)))
+        if (check_with_uid && ordered_hashmap_get(todo_uids, UID_TO_PTR(gid)))
                 return 0;
 
         if (hashmap_contains(database_by_gid, GID_TO_PTR(gid)))
                 return 0;
 
-        if (hashmap_contains(database_by_uid, UID_TO_PTR(gid)))
+        if (check_with_uid && hashmap_contains(database_by_uid, UID_TO_PTR(gid)))
                 return 0;
 
         if (!arg_root) {
@@ -1194,12 +1180,14 @@ static int gid_is_ok(gid_t gid) {
                 if (!IN_SET(errno, 0, ENOENT))
                         return -errno;
 
-                errno = 0;
-                p = getpwuid((uid_t) gid);
-                if (p)
-                        return 0;
-                if (!IN_SET(errno, 0, ENOENT))
-                        return -errno;
+                if (check_with_uid) {
+                        errno = 0;
+                        p = getpwuid((uid_t) gid);
+                        if (p)
+                                return 0;
+                        if (!IN_SET(errno, 0, ENOENT))
+                                return -errno;
+                }
         }
 
         return 1;
@@ -1250,7 +1238,7 @@ static int add_group(Item *i) {
 
         /* Try to use the suggested numeric GID */
         if (i->gid_set) {
-                r = gid_is_ok(i->gid);
+                r = gid_is_ok(i->gid, false);
                 if (r < 0)
                         return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
                 if (i->id_set_strict) {
@@ -1273,7 +1261,7 @@ static int add_group(Item *i) {
 
         /* Try to reuse the numeric uid, if there's one */
         if (!i->gid_set && i->uid_set) {
-                r = gid_is_ok((gid_t) i->uid);
+                r = gid_is_ok((gid_t) i->uid, true);
                 if (r < 0)
                         return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
                 if (r > 0) {
@@ -1291,7 +1279,7 @@ static int add_group(Item *i) {
                         if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
                                 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
                         else {
-                                r = gid_is_ok(c);
+                                r = gid_is_ok(c, true);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
                                 else if (r > 0) {
@@ -1313,7 +1301,7 @@ static int add_group(Item *i) {
                         if (r < 0)
                                 return log_error_errno(r, "No free group ID available for %s.", i->name);
 
-                        r = gid_is_ok(search_uid);
+                        r = gid_is_ok(search_uid, true);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to verify GID " GID_FMT ": %m", i->gid);
                         else if (r > 0)
@@ -1346,9 +1334,11 @@ static int process_item(Item *i) {
         switch (i->type) {
 
         case ADD_USER: {
-                Item *j;
+                Item *j = NULL;
+
+                if (!i->gid_set)
+                        j = ordered_hashmap_get(groups, i->group_name ?: i->name);
 
-                j = ordered_hashmap_get(groups, i->group_name ?: i->name);
                 if (j && j->todo_group) {
                         /* When a group with the target name is already in queue,
                          * use the information about the group and do not create
index 4c56a7d52008a7b0f29bb7d7b9b808ae9a4534b2..e0583cfbaba762ce1ff375691a16053ea72521e0 100644 (file)
@@ -1027,6 +1027,44 @@ TEST(path_startswith_strv) {
         assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL));
 }
 
+static void test_path_glob_can_match_one(const char *pattern, const char *prefix, const char *expected) {
+        _cleanup_free_ char *result = NULL;
+
+        log_debug("%s(%s, %s, %s)", __func__, pattern, prefix, strnull(expected));
+
+        assert_se(path_glob_can_match(pattern, prefix, &result) == !!expected);
+        assert_se(streq_ptr(result, expected));
+}
+
+TEST(path_glob_can_match) {
+        test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa/bbb", NULL);
+        test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
+        test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge", "/foo/hoge/aaa");
+        test_path_glob_can_match_one("/foo/hoge/aaa", "/foo", "/foo/hoge/aaa");
+        test_path_glob_can_match_one("/foo/hoge/aaa", "/", "/foo/hoge/aaa");
+
+        test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa/bbb", NULL);
+        test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
+        test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge", "/foo/hoge/aaa");
+        test_path_glob_can_match_one("/foo/*/aaa", "/foo", "/foo/*/aaa");
+        test_path_glob_can_match_one("/foo/*/aaa", "/", "/foo/*/aaa");
+
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa/bbb", NULL);
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa", "/foo/xxx/yyy/aaa");
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy", "/foo/xxx/yyy/aaa");
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx", "/foo/xxx/*/aaa");
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/foo", "/foo/*/*/aaa");
+        test_path_glob_can_match_one("/foo/*/*/aaa", "/", "/foo/*/*/aaa");
+
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb/ccc", NULL);
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb", "/foo/xxx/aaa/bbb");
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/ccc", NULL);
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa", "/foo/xxx/aaa/*");
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx", "/foo/xxx/aaa/*");
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/foo", "/foo/*/aaa/*");
+        test_path_glob_can_match_one("/foo/*/aaa/*", "/", "/foo/*/aaa/*");
+}
+
 TEST(print_MAX) {
         log_info("PATH_MAX=%zu\n"
                  "FILENAME_MAX=%zu\n"
index 85cf5201c6a1d9960debfb60ddcfef89e9bd6460..d2c126212182993f56aa714f2c3be3c7dc0d709d 100644 (file)
@@ -704,7 +704,7 @@ static int cd_media_toc(Context *c) {
         /* Take care to not iterate beyond the last valid track as specified in
          * the TOC, but also avoid going beyond the TOC length, just in case
          * the last track number is invalidly large */
-        for (size_t i = 4; i + 8 < len && num_tracks > 0; i += 8, --num_tracks) {
+        for (size_t i = 4; i + 8 <= len && num_tracks > 0; i += 8, --num_tracks) {
                 bool is_data_track;
                 uint32_t block;
 
index 693f5cd3a60279a5699928b3a3807307d67ea431..3863808fb030b51d3a432a9aaf24400356b6415d 100644 (file)
@@ -264,7 +264,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
                         "Link\0"
                         "SR-IOV\0",
                         config_item_perf_lookup, link_config_gperf_lookup,
-                        CONFIG_PARSE_WARN, config, &stats_by_path);
+                        CONFIG_PARSE_WARN, config, &stats_by_path,
+                        NULL);
         if (r < 0)
                 return r; /* config_parse_many() logs internally. */
 
index 1924fcc4ad4d4a8155d90ed02481d27f329013d8..8d652e46feebdbf0bc9635ea3e146412be54e4c4 100644 (file)
@@ -207,8 +207,8 @@ static void builtin_hwdb_exit(void) {
 }
 
 /* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_hwdb_validate(void) {
-        if (hwdb_validate(hwdb)) {
+static bool builtin_hwdb_should_reload(void) {
+        if (hwdb_should_reload(hwdb)) {
                 log_debug("hwdb needs reloading.");
                 return true;
         }
@@ -221,6 +221,6 @@ const UdevBuiltin udev_builtin_hwdb = {
         .cmd = builtin_hwdb,
         .init = builtin_hwdb_init,
         .exit = builtin_hwdb_exit,
-        .validate = builtin_hwdb_validate,
+        .should_reload = builtin_hwdb_should_reload,
         .help = "Hardware database",
 };
index 85afd3b6ec92852eeb251f32f66bc2def4bd02ec..0ba2d2bd13d125db5ffa053e8cf28108d495779b 100644 (file)
@@ -56,7 +56,7 @@ static void builtin_kmod_exit(void) {
 }
 
 /* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_kmod_validate(void) {
+static bool builtin_kmod_should_reload(void) {
         if (!ctx)
                 return false;
 
@@ -73,7 +73,7 @@ const UdevBuiltin udev_builtin_kmod = {
         .cmd = builtin_kmod,
         .init = builtin_kmod_init,
         .exit = builtin_kmod_exit,
-        .validate = builtin_kmod_validate,
+        .should_reload = builtin_kmod_should_reload,
         .help = "Kernel module loader",
         .run_once = false,
 };
index 45387b2bdbedee88e8901a3cca0cd491fb9b5bef..33fce6e140613fabd172c166b81adb3535acce3d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pci_regs.h>
 
 #include "alloc-util.h"
+#include "chase-symlinks.h"
 #include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
@@ -52,6 +53,7 @@ typedef enum NetNameType {
         NET_XENVIF,
         NET_PLATFORM,
         NET_NETDEVSIM,
+        NET_DEVICETREE,
 } NetNameType;
 
 typedef struct NetNames {
@@ -70,6 +72,7 @@ typedef struct NetNames {
         char xen_slot[ALTIFNAMSIZ];
         char platform_path[ALTIFNAMSIZ];
         char netdevsim_path[ALTIFNAMSIZ];
+        char devicetree_onboard[ALTIFNAMSIZ];
 } NetNames;
 
 /* skip intermediate virtio devices */
@@ -600,6 +603,94 @@ static int names_platform(sd_device *dev, NetNames *names, bool test) {
         return 0;
 }
 
+static int dev_devicetree_onboard(sd_device *dev, NetNames *names) {
+        _cleanup_(sd_device_unrefp) sd_device *aliases_dev = NULL, *ofnode_dev = NULL, *devicetree_dev = NULL;
+        const char *alias, *ofnode_path, *ofnode_syspath, *devicetree_syspath;
+        sd_device *parent;
+        int r;
+
+        if (!naming_scheme_has(NAMING_DEVICETREE_ALIASES))
+                return 0;
+
+        /* check if our direct parent has an of_node */
+        r = sd_device_get_parent(dev, &parent);
+        if (r < 0)
+                return r;
+
+        r = sd_device_new_child(&ofnode_dev, parent, "of_node");
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_syspath(ofnode_dev, &ofnode_syspath);
+        if (r < 0)
+                return r;
+
+        /* /proc/device-tree should be a symlink to /sys/firmware/devicetree/base. */
+        r = sd_device_new_from_path(&devicetree_dev, "/proc/device-tree");
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_syspath(devicetree_dev, &devicetree_syspath);
+        if (r < 0)
+                return r;
+
+        /*
+         * Example paths:
+         * devicetree_syspath = /sys/firmware/devicetree/base
+         * ofnode_syspath = /sys/firmware/devicetree/base/soc/ethernet@deadbeef
+         * ofnode_path = soc/ethernet@deadbeef
+         */
+        ofnode_path = path_startswith(ofnode_syspath, devicetree_syspath);
+        if (!ofnode_path)
+                return -ENOENT;
+
+        /* Get back our leading / to match the contents of the aliases */
+        ofnode_path--;
+        assert(path_is_absolute(ofnode_path));
+
+        r = sd_device_new_child(&aliases_dev, devicetree_dev, "aliases");
+        if (r < 0)
+                return r;
+
+        FOREACH_DEVICE_SYSATTR(aliases_dev, alias) {
+                const char *alias_path, *alias_index, *conflict;
+                unsigned i;
+
+                alias_index = startswith(alias, "ethernet");
+                if (!alias_index)
+                        continue;
+
+                if (sd_device_get_sysattr_value(aliases_dev, alias, &alias_path) < 0)
+                        continue;
+
+                if (!path_equal(ofnode_path, alias_path))
+                        continue;
+
+                /* If there's no index, we default to 0... */
+                if (isempty(alias_index)) {
+                        i = 0;
+                        conflict = "ethernet0";
+                } else {
+                        r = safe_atou(alias_index, &i);
+                        if (r < 0)
+                                return log_device_debug_errno(dev, r,
+                                                "Could not get index of alias %s: %m", alias);
+                        conflict = "ethernet";
+                }
+
+                /* ...but make sure we don't have an alias conflict */
+                if (i == 0 && sd_device_get_sysattr_value(aliases_dev, conflict, NULL) >= 0)
+                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
+                                        "Ethernet alias conflict: ethernet and ethernet0 both exist");
+
+                xsprintf(names->devicetree_onboard, "d%u", i);
+                names->type = NET_DEVICETREE;
+                return 0;
+        }
+
+        return -ENOENT;
+}
+
 static int names_pci(sd_device *dev, const LinkInfo *info, NetNames *names) {
         _cleanup_(sd_device_unrefp) sd_device *physfn_pcidev = NULL;
         _cleanup_free_ char *virtfn_suffix = NULL;
@@ -1036,6 +1127,15 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
                 ieee_oui(dev, &info, test);
         }
 
+        /* get devicetree aliases; only ethernet supported for now  */
+        if (streq(prefix, "en") && dev_devicetree_onboard(dev, &names) >= 0 &&
+            names.type == NET_DEVICETREE) {
+                char str[ALTIFNAMSIZ];
+
+                if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.devicetree_onboard))
+                        udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
+        }
+
         /* get path names for Linux on System z network devices */
         if (names_ccw(dev, &names) >= 0 && names.type == NET_CCW) {
                 char str[ALTIFNAMSIZ];
index bad4e994b9d3afeae0c90abf5de72bec71d382aa..ea7b1c5f602260a22c1cc67c6d93a19df0adfc5e 100644 (file)
@@ -74,7 +74,7 @@ static void builtin_net_setup_link_exit(void) {
         log_debug("Unloaded link configuration context.");
 }
 
-static bool builtin_net_setup_link_validate(void) {
+static bool builtin_net_setup_link_should_reload(void) {
         if (!ctx)
                 return false;
 
@@ -91,7 +91,7 @@ const UdevBuiltin udev_builtin_net_setup_link = {
         .cmd = builtin_net_setup_link,
         .init = builtin_net_setup_link_init,
         .exit = builtin_net_setup_link_exit,
-        .validate = builtin_net_setup_link_validate,
+        .should_reload = builtin_net_setup_link_should_reload,
         .help = "Configure network link",
         .run_once = false,
 };
index bf827097719af7f2d259250324dc37c5fb77f7ac..c98c6fa714fcc6a815827a3c141df8c23ced4bf9 100644 (file)
@@ -53,9 +53,9 @@ void udev_builtin_exit(void) {
         initialized = false;
 }
 
-bool udev_builtin_validate(void) {
+bool udev_builtin_should_reload(void) {
         for (UdevBuiltinCommand i = 0; i < _UDEV_BUILTIN_MAX; i++)
-                if (builtins[i] && builtins[i]->validate && builtins[i]->validate())
+                if (builtins[i] && builtins[i]->should_reload && builtins[i]->should_reload())
                         return true;
         return false;
 }
index b0f2f919a9ab193c7023026023cb81fc8062c6df..bcfec03aaeb01ae043f0e4334c09495a19f644cd 100644 (file)
@@ -34,7 +34,7 @@ typedef struct UdevBuiltin {
         const char *help;
         int (*init)(void);
         void (*exit)(void);
-        bool (*validate)(void);
+        bool (*should_reload)(void);
         bool run_once;
 } UdevBuiltin;
 
@@ -76,7 +76,7 @@ const char *udev_builtin_name(UdevBuiltinCommand cmd);
 bool udev_builtin_run_once(UdevBuiltinCommand cmd);
 int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test);
 void udev_builtin_list(void);
-bool udev_builtin_validate(void);
+bool udev_builtin_should_reload(void);
 int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val);
 int udev_builtin_hwdb_lookup(sd_device *dev, const char *prefix, const char *modalias,
                              const char *filter, bool test);
index 0a68b7e6ac18356f7eda1c34eace8177aa449176..a6926bbfb71d97b4cf0d0ef9d15edfc5269dfb6a 100644 (file)
@@ -368,7 +368,7 @@ static void manager_reload(Manager *manager, bool force) {
         mac_selinux_maybe_reload();
 
         /* Nothing changed. It is not necessary to reload. */
-        if (!udev_rules_should_reload(manager->rules) && !udev_builtin_validate())
+        if (!udev_rules_should_reload(manager->rules) && !udev_builtin_should_reload())
                 return;
 
         sd_notify(false,
@@ -797,6 +797,8 @@ static int worker_spawn(Manager *manager, Event *event) {
         if (r < 0)
                 return r;
 
+        (void) sd_device_monitor_set_description(worker_monitor, "worker");
+
         /* allow the main daemon netlink address to send devices to the worker */
         r = device_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
         if (r < 0)
@@ -1919,6 +1921,8 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent) {
                         log_warning_errno(r, "Failed to set receive buffer size for device monitor, ignoring: %m");
         }
 
+        (void) sd_device_monitor_set_description(manager->monitor, "manager");
+
         r = device_monitor_enable_receiving(manager->monitor);
         if (r < 0)
                 return log_error_errno(r, "Failed to bind netlink socket: %m");
index d5f3228065c2b200873ee8de52a963c5b5d3ec0d..309941f58defe87980d182fb650f36e12d9b4ada 100644 (file)
@@ -171,6 +171,7 @@ User=
 Group=
 PacketInfo=
 VNetHeader=
+KeepCarrier=
 [IPVLAN]
 Mode=
 Flags=
@@ -184,6 +185,7 @@ PacketInfo=
 VNetHeader=
 Group=
 User=
+KeepCarrier=
 [NetDev]
 Kind=
 MACAddress=
index 4b5ba622fa6f31e6c33e15299d271dd651c0b772..0a5ba11f89e08e6a4439306a518236d370102288 100755 (executable)
@@ -291,8 +291,8 @@ Priority=23
         self.assertEqual(self.read_attr('port2', 'brport/path_cost'), '555')
         self.assertEqual(self.read_attr('port2', 'brport/multicast_fast_leave'), '1')
         self.assertEqual(self.read_attr('port2', 'brport/unicast_flood'), '1')
-        self.assertEqual(self.read_attr('port2', 'brport/bpdu_guard'), '1')
-        self.assertEqual(self.read_attr('port2', 'brport/root_block'), '1')
+        self.assertEqual(self.read_attr('port2', 'brport/bpdu_guard'), '0')
+        self.assertEqual(self.read_attr('port2', 'brport/root_block'), '0')
 
 class ClientTestBase(NetworkdTestingUtilities):
     """Provide common methods for testing networkd against servers."""
index b208825e67425b4f8ec4d2239ed25c9d242557b8..5dec5e28dec1e04b1270ee432a28d7c0b19c71f5 100644 (file)
@@ -712,6 +712,13 @@ EOF
         chmod +x "$initdir/opt/script1.sh"
         echo MARKER=1 >"$initdir/usr/lib/systemd/system/other_file"
         mksquashfs "$initdir" "$oldinitdir/usr/share/app1.raw" -noappend
+
+        export initdir="$TESTDIR/app-nodistro"
+        mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system"
+        ( echo "ID=_any"
+          echo "ARCHITECTURE=_any" ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro"
+        echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file"
+        mksquashfs "$initdir" "$oldinitdir/usr/share/app-nodistro.raw" -noappend
     )
 }
 
index 07ef254ddabed4e6ef239b76e152f2d58067113d..dbeb04ea0452866e58a98dbe0683a5dfc885598a 100644 (file)
@@ -2,6 +2,9 @@
 [Match]
 Name=bridge99
 
+[Link]
+MTUBytes=9000
+
 [Network]
 Address=192.168.0.15/24
 Gateway=192.168.0.1
diff --git a/test/test-network/conf/25-dhcp-client-decline.network b/test/test-network/conf/25-dhcp-client-decline.network
deleted file mode 100644 (file)
index ea1a2d0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Match]
-Name=veth99
-
-[Network]
-DHCP=ipv4
-IPv6AcceptRA=false
-
-[DHCPv4]
-SendDecline=yes
index e146337c5e4471bf12fb9d4f0e86a1c06e8ad5d5..fd0d8942bd3517c763d34eb263fd5340ea9d3c23 100644 (file)
@@ -10,6 +10,7 @@ DHCPPrefixDelegation=yes
 
 [DHCPv4]
 Use6RD=yes
+SendDecline=yes
 
 [DHCPPrefixDelegation]
 UplinkInterface=:self
diff --git a/test/test-network/conf/25-qdisc-clsact-and-htb.network b/test/test-network/conf/25-qdisc-clsact-and-htb.network
deleted file mode 100644 (file)
index c91666d..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-[Match]
-Name=dummy98
-
-[Network]
-IPv6AcceptRA=no
-Address=10.1.2.3/16
-
-[QDisc]
-Parent=clsact
-
-[HierarchyTokenBucket]
-Parent=root
-Handle=0002
-DefaultClass=30
-RateToQuantum=20
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0030
-Priority=1
-QuantumBytes=4000
-MTUBytes=1700
-OverheadBytes=100
-Rate=1M
-BufferBytes=123456
-CeilRate=0.5M
-CeilBufferBytes=123457
-
-[NetworkEmulator]
-Parent=2:30
-Handle=0030
-DelaySec=50ms
-DelayJitterSec=10ms
-LossRate=20%
-PacketLimit=100
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0031
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[TrivialLinkEqualizer]
-Parent=2:31
-Handle=0031
-Id=1
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0032
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[FairQueueing]
-Parent=2:32
-Handle=0032
-PacketLimit=1000
-FlowLimit=200
-QuantumBytes=1500
-InitialQuantumBytes=13000
-MaximumRate=1M
-Buckets=512
-OrphanMask=511
-Pacing=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0033
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[ControlledDelay]
-Parent=2:33
-Handle=0033
-PacketLimit=2000
-TargetSec=10ms
-IntervalSec=50ms
-ECN=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0034
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[FairQueueingControlledDelay]
-Parent=2:34
-Handle=0034
-PacketLimit=20480
-MemoryLimitBytes=64M
-Flows=2048
-TargetSec=10ms
-IntervalSec=200ms
-QuantumBytes=1400
-ECN=yes
-CEThresholdSec=100ms
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0035
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[TokenBucketFilter]
-Parent=2:35
-Handle=0035
-Rate=1G
-BurstBytes=5000
-LatencySec=70msec
-PeakRate=100G
-MTUBytes=1000000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0036
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[StochasticFairnessQueueing]
-Parent=2:36
-Handle=0036
-PerturbPeriodSec=5sec
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0037
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFO]
-Parent=2:37
-Handle=0037
-PacketLimit=100000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0038
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[GenericRandomEarlyDetection]
-Parent=2:38
-Handle=0038
-VirtualQueues=12
-DefaultVirtualQueue=10
-GenericRIO=yes
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:0039
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[StochasticFairBlue]
-Parent=2:39
-Handle=0039
-PacketLimit=200000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003a
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[BFIFO]
-Parent=2:3a
-Handle=003a
-LimitBytes=1000000
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003b
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFOHeadDrop]
-Parent=2:3b
-Handle=003b
-PacketLimit=1023
-
-[HierarchyTokenBucketClass]
-Parent=root
-ClassId=0002:003c
-Priority=1
-Rate=1M
-CeilRate=0.5M
-
-[PFIFOFast]
-Parent=2:3c
-Handle=003c
diff --git a/test/test-network/conf/25-qdisc-clsact.network b/test/test-network/conf/25-qdisc-clsact.network
new file mode 100644 (file)
index 0000000..8a16618
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[QDisc]
+Parent=clsact
diff --git a/test/test-network/conf/25-qdisc-codel.network b/test/test-network/conf/25-qdisc-codel.network
new file mode 100644 (file)
index 0000000..a332fa8
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[ControlledDelay]
+Parent=root
+Handle=0033
+PacketLimit=2000
+TargetSec=10ms
+IntervalSec=50ms
+ECN=yes
+CEThresholdSec=100ms
diff --git a/test/test-network/conf/25-qdisc-fq.network b/test/test-network/conf/25-qdisc-fq.network
new file mode 100644 (file)
index 0000000..5539a64
--- /dev/null
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[FairQueueing]
+Parent=root
+Handle=0032
+PacketLimit=1000
+FlowLimit=200
+QuantumBytes=1500
+InitialQuantumBytes=13000
+MaximumRate=1M
+Buckets=512
+OrphanMask=511
+Pacing=yes
+CEThresholdSec=100ms
diff --git a/test/test-network/conf/25-qdisc-fq_codel.network b/test/test-network/conf/25-qdisc-fq_codel.network
new file mode 100644 (file)
index 0000000..0e7d62d
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[FairQueueingControlledDelay]
+Parent=root
+Handle=0034
+PacketLimit=20480
+MemoryLimitBytes=64M
+Flows=2048
+TargetSec=10ms
+IntervalSec=200ms
+QuantumBytes=1400
+ECN=yes
+CEThresholdSec=100ms
diff --git a/test/test-network/conf/25-qdisc-gred.network b/test/test-network/conf/25-qdisc-gred.network
new file mode 100644 (file)
index 0000000..a49955f
--- /dev/null
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[GenericRandomEarlyDetection]
+Parent=root
+Handle=0038
+VirtualQueues=12
+DefaultVirtualQueue=10
+GenericRIO=yes
diff --git a/test/test-network/conf/25-qdisc-htb-fifo.network b/test/test-network/conf/25-qdisc-htb-fifo.network
new file mode 100644 (file)
index 0000000..1e092a9
--- /dev/null
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[HierarchyTokenBucket]
+Parent=root
+Handle=0002
+DefaultClass=30
+RateToQuantum=20
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:0037
+Priority=1
+Rate=1M
+CeilRate=0.5M
+QuantumBytes=4000
+MTUBytes=1700
+OverheadBytes=100
+BufferBytes=123456
+CeilBufferBytes=123457
+
+[PFIFO]
+Parent=2:37
+Handle=0037
+PacketLimit=100000
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003a
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[BFIFO]
+Parent=2:3a
+Handle=003a
+LimitBytes=1000000
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003b
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOHeadDrop]
+Parent=2:3b
+Handle=003b
+PacketLimit=1023
+
+[HierarchyTokenBucketClass]
+Parent=root
+ClassId=0002:003c
+Priority=1
+Rate=1M
+CeilRate=0.5M
+
+[PFIFOFast]
+Parent=2:3c
+Handle=003c
diff --git a/test/test-network/conf/25-qdisc-ingress.network b/test/test-network/conf/25-qdisc-ingress.network
new file mode 100644 (file)
index 0000000..6fb5fef
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=test1
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.4/16
+
+[QDisc]
+Parent=ingress
similarity index 84%
rename from test/test-network/conf/25-qdisc-ingress-netem-compat.network
rename to test/test-network/conf/25-qdisc-netem-compat.network
index d895f7f34fe5756b17e70fc807a2b56f760dd959..15e0f7f36767d64e7cf1fe28b29ef4a95efb48e5 100644 (file)
@@ -12,6 +12,3 @@ NetworkEmulatorDelaySec=50ms
 NetworkEmulatorDelayJitterSec=10ms
 NetworkEmulatorLossRate=20%
 NetworkEmulatorPacketLimit=100
-
-[TrafficControlQueueingDiscipline]
-Parent=ingress
diff --git a/test/test-network/conf/25-qdisc-netem.network b/test/test-network/conf/25-qdisc-netem.network
new file mode 100644 (file)
index 0000000..9848788
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[NetworkEmulator]
+Parent=root
+Handle=0030
+DelaySec=50ms
+DelayJitterSec=10ms
+LossRate=20%
+PacketLimit=100
index 1c8dbc2461dfb916a084cbdb6b473391c452e334..b09e99c4f2634c2a4a139b24106b9989db487b8c 100644 (file)
@@ -1,10 +1,10 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [Match]
-Name=test1
+Name=dummy98
 
 [Network]
 IPv6AcceptRA=no
-Address=10.1.2.4/16
+Address=10.1.2.3/16
 
 [QuickFairQueueing]
 Parent=root
diff --git a/test/test-network/conf/25-qdisc-sfb.network b/test/test-network/conf/25-qdisc-sfb.network
new file mode 100644 (file)
index 0000000..bfcda00
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[StochasticFairBlue]
+Parent=root
+Handle=0039
+PacketLimit=200000
diff --git a/test/test-network/conf/25-qdisc-sfq.network b/test/test-network/conf/25-qdisc-sfq.network
new file mode 100644 (file)
index 0000000..263cd6d
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[StochasticFairnessQueueing]
+Parent=root
+Handle=0036
+PerturbPeriodSec=5sec
diff --git a/test/test-network/conf/25-qdisc-tbf.network b/test/test-network/conf/25-qdisc-tbf.network
new file mode 100644 (file)
index 0000000..c5f28fb
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[TokenBucketFilter]
+Parent=root
+Handle=0035
+Rate=1G
+BurstBytes=5000
+LatencySec=70msec
+PeakRate=100G
+MTUBytes=1000000
diff --git a/test/test-network/conf/25-qdisc-teql.network b/test/test-network/conf/25-qdisc-teql.network
new file mode 100644 (file)
index 0000000..ed7e21f
--- /dev/null
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+
+[TrivialLinkEqualizer]
+Parent=root
+Handle=0031
+Id=1
index 5c1f97be9ea306356966c3fe24657db47f26227b..5cbfd0e5b1c4d2355012507f86b84a59369d797d 100644 (file)
@@ -1,9 +1,10 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [NetDev]
-Name=tap99
+Name=testtap99
 Kind=tap
 
 [Tap]
 MultiQueue=true
 PacketInfo=true
 VNetHeader=true
+KeepCarrier=yes
index ed25026a95925898311312939ccfe0700b58ebc4..a354ebb2b219d1e31b0f89f1552e26354f820d3c 100644 (file)
@@ -1,9 +1,10 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 [NetDev]
-Name=tun99
+Name=testtun99
 Kind=tun
 
 [Tun]
 MultiQueue=true
 PacketInfo=true
 VNetHeader=true
+KeepCarrier=yes
index 8858cbf0008f176f744bc509f6a67426a2edca82..cdb3daa2b1bed74d96a27838fcde6249eba4be0b 100644 (file)
@@ -2,6 +2,9 @@
 [Match]
 Name=dummy98
 
+[Link]
+MTUBytes=9000
+
 [Network]
 Bridge=bridge99
 
index 26ab7d8af6abba835ed9a4842fe8d3e400ea6e58..42b197eeef12060557e5ac04fb4dafab1229d576 100644 (file)
@@ -2,6 +2,9 @@
 [Match]
 Name=test1
 
+[Link]
+MTUBytes=9000
+
 [Network]
 Bridge=bridge99
 
index 8ec0190bcb830b5cf1f6b11c9e8f9c7532850864..71521258d3fdb17a9fa7589fda0c2050757b9d3b 100644 (file)
@@ -22,6 +22,8 @@ Name=nlmon99
 Name=xfrm98 xfrm99
 Name=vxlan98
 Name=hogehogehogehogehogehoge
+Name=testtun99
+Name=testtap99
 
 [Network]
 LinkLocalAddressing=yes
index 9266441944cb30537005b1073ae9dcd737e9aaa4..3c1b3e0c1c17da50d2a5681d397a3ac64e276337 100755 (executable)
@@ -13,6 +13,7 @@ import errno
 import itertools
 import os
 import pathlib
+import psutil
 import re
 import shutil
 import signal
@@ -38,13 +39,16 @@ which_paths = ':'.join(systemd_lib_paths + os.getenv('PATH', os.defpath).lstrip(
 
 networkd_bin = shutil.which('systemd-networkd', path=which_paths)
 resolved_bin = shutil.which('systemd-resolved', path=which_paths)
+timesyncd_bin = shutil.which('systemd-timesyncd', path=which_paths)
 udevd_bin = shutil.which('systemd-udevd', path=which_paths)
 wait_online_bin = shutil.which('systemd-networkd-wait-online', path=which_paths)
 networkctl_bin = shutil.which('networkctl', path=which_paths)
 resolvectl_bin = shutil.which('resolvectl', path=which_paths)
 timedatectl_bin = shutil.which('timedatectl', path=which_paths)
+udevadm_bin = shutil.which('udevadm', path=which_paths)
 
 use_valgrind = False
+valgrind_cmd = ''
 enable_debug = True
 env = {}
 wait_online_env = {}
@@ -92,33 +96,41 @@ def mkdir_p(path):
 def touch(path):
     pathlib.Path(path).touch()
 
-def check_output(*command, text=True, **kwargs):
+def check_output(*command, **kwargs):
     # This checks the result and returns stdout (and stderr) on success.
     command = command[0].split() + list(command[1:])
-    return subprocess.run(command, check=True, universal_newlines=text, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs).stdout.rstrip()
-
-def call(*command, text=True, **kwargs):
+    ret = subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs)
+    if ret.returncode == 0:
+        return ret.stdout.rstrip()
+    # When returncode != 0, print stdout and stderr, then trigger CalledProcessError.
+    print(ret.stdout)
+    ret.check_returncode()
+
+def call(*command, **kwargs):
     # This returns returncode. stdout and stderr are merged and shown in console
     command = command[0].split() + list(command[1:])
-    return subprocess.run(command, check=False, universal_newlines=text, stderr=subprocess.STDOUT, **kwargs).returncode
+    return subprocess.run(command, check=False, universal_newlines=True, stderr=subprocess.STDOUT, **kwargs).returncode
 
-def call_quiet(*command, text=True, **kwargs):
+def call_quiet(*command, **kwargs):
     command = command[0].split() + list(command[1:])
-    return subprocess.run(command, check=False, universal_newlines=text, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
+    return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs).returncode
 
-def run(*command, text=True, **kwargs):
+def run(*command, **kwargs):
     # This returns CompletedProcess instance.
     command = command[0].split() + list(command[1:])
-    return subprocess.run(command, check=False, universal_newlines=text, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
+    return subprocess.run(command, check=False, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
 
-def is_module_available(module_name):
-    lsmod_output = check_output('lsmod')
-    module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
-    return module_re.search(lsmod_output) or call_quiet('modprobe', module_name) == 0
+def is_module_available(*module_names):
+    for module_name in module_names:
+        lsmod_output = check_output('lsmod')
+        module_re = re.compile(rf'^{re.escape(module_name)}\b', re.MULTILINE)
+        if not module_re.search(lsmod_output) and call_quiet('modprobe', module_name) != 0:
+            return False
+    return True
 
-def expectedFailureIfModuleIsNotAvailable(module_name):
+def expectedFailureIfModuleIsNotAvailable(*module_names):
     def f(func):
-        return func if is_module_available(module_name) else unittest.expectedFailure(func)
+        return func if is_module_available(*module_names) else unittest.expectedFailure(func)
 
     return f
 
@@ -231,53 +243,8 @@ def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
 
     return f
 
-def expectedFailureIfCAKEIsNotAvailable():
-    def f(func):
-        call_quiet('ip link add dummy98 type dummy')
-        rc = call_quiet('tc qdisc add dev dummy98 parent root cake')
-        remove_link('dummy98')
-        return func if rc == 0 else unittest.expectedFailure(func)
-
-    return f
-
-def expectedFailureIfPIEIsNotAvailable():
-    def f(func):
-        call_quiet('ip link add dummy98 type dummy')
-        rc = call_quiet('tc qdisc add dev dummy98 parent root pie')
-        remove_link('dummy98')
-        return func if rc == 0 else unittest.expectedFailure(func)
-
-    return f
-
-def expectedFailureIfHHFIsNotAvailable():
-    def f(func):
-        call_quiet('ip link add dummy98 type dummy')
-        rc = call_quiet('tc qdisc add dev dummy98 parent root hhf')
-        remove_link('dummy98')
-        return func if rc == 0 else unittest.expectedFailure(func)
-
-    return f
-
-def expectedFailureIfETSIsNotAvailable():
-    def f(func):
-        call_quiet('ip link add dummy98 type dummy')
-        rc = call_quiet('tc qdisc add dev dummy98 parent root ets bands 10')
-        remove_link('dummy98')
-        return func if rc == 0 else unittest.expectedFailure(func)
-
-    return f
-
-def expectedFailureIfFQPIEIsNotAvailable():
-    def f(func):
-        call_quiet('ip link add dummy98 type dummy')
-        rc = call_quiet('tc qdisc add dev dummy98 parent root fq_pie')
-        remove_link('dummy98')
-        return func if rc == 0 else unittest.expectedFailure(func)
-
-    return f
-
 def udev_reload():
-    check_output('udevadm control --reload')
+    check_output(*udevadm_cmd, 'control', '--reload')
 
 def copy_network_unit(*units, copy_dropins=True):
     """
@@ -371,7 +338,7 @@ def clear_udev_rules():
 
 def save_active_units():
     for u in ['systemd-networkd.socket', 'systemd-networkd.service',
-              'systemd-resolved.service',
+              'systemd-resolved.service', 'systemd-timesyncd.service',
               'firewalld.service']:
         if call(f'systemctl is-active --quiet {u}') == 0:
             call(f'systemctl stop {u}')
@@ -383,6 +350,49 @@ def restore_active_units():
     for u in active_units:
         call(f'systemctl restart {u}')
 
+def create_unit_dropin(unit, contents):
+    mkdir_p(f'/run/systemd/system/{unit}.d')
+    with open(f'/run/systemd/system/{unit}.d/00-override.conf', mode='w', encoding='utf-8') as f:
+        f.write('\n'.join(contents))
+
+def create_service_dropin(service, command, reload_command=None, additional_settings=None):
+    drop_in = [
+        '[Service]',
+        'ExecStart=',
+        f'ExecStart=!!{valgrind_cmd}{command}',
+    ]
+    if reload_command:
+        drop_in += [
+            'ExecReload=',
+            f'ExecReload={valgrind_cmd}{reload_command}',
+        ]
+    if enable_debug:
+        drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
+    if asan_options:
+        drop_in += [f'Environment=ASAN_OPTIONS="{asan_options}"']
+    if lsan_options:
+        drop_in += [f'Environment=LSAN_OPTIONS="{lsan_options}"']
+    if ubsan_options:
+        drop_in += [f'Environment=UBSAN_OPTIONS="{ubsan_options}"']
+    if asan_options or lsan_options or ubsan_options:
+        drop_in += ['SystemCallFilter=']
+    if use_valgrind or asan_options or lsan_options or ubsan_options:
+        drop_in += ['MemoryDenyWriteExecute=no']
+    if use_valgrind:
+        drop_in += [
+            'Environment=SYSTEMD_MEMPOOL=0',
+            'PrivateTmp=yes',
+        ]
+    if with_coverage:
+        drop_in += [
+            'ProtectSystem=no',
+            'ProtectHome=no',
+        ]
+    if additional_settings:
+        drop_in += additional_settings
+
+    create_unit_dropin(f'{service}.service', drop_in)
+
 def link_exists(link):
     return os.path.exists(os.path.join('/sys/class/net', link, 'ifindex'))
 
@@ -497,14 +507,14 @@ def flush_l2tp_tunnels():
 
 def save_timezone():
     global saved_timezone
-    r = run('timedatectl show --value --property Timezone')
+    r = run(*timedatectl_cmd, 'show', '--value', '--property', 'Timezone', env=env)
     if r.returncode == 0:
         saved_timezone = r.stdout.rstrip()
         print(f'### Saved timezone: {saved_timezone}')
 
 def restore_timezone():
     if saved_timezone:
-        call(f'timedatectl set-timezone {saved_timezone}')
+        call(*timedatectl_cmd, 'set-timezone', f'{saved_timezone}', env=env)
 
 def read_link_attr(*args):
     with open(os.path.join('/sys/class/net', *args), encoding='utf-8') as f:
@@ -595,8 +605,14 @@ def start_networkd():
     check_output('systemctl start systemd-networkd')
 
 def restart_networkd(show_logs=True):
-    stop_networkd(show_logs)
-    start_networkd()
+    if show_logs:
+        invocation_id = check_output('systemctl show systemd-networkd.service -p InvocationID --value')
+    check_output('systemctl restart systemd-networkd.service')
+    if show_logs:
+        print(check_output('journalctl _SYSTEMD_INVOCATION_ID=' + invocation_id))
+
+def networkd_pid():
+    return int(check_output('systemctl show --value -p MainPID systemd-networkd.service'))
 
 def networkctl_reconfigure(*links):
     check_output(*networkctl_cmd, 'reconfigure', *links, env=env)
@@ -657,93 +673,40 @@ def setUpModule():
     save_routing_policy_rules()
     save_timezone()
 
-    drop_in = [
-        '[Unit]',
-        'StartLimitIntervalSec=0',
-        '[Service]',
-        'Restart=no',
-        'ExecStart=',
-        'ExecReload=',
-    ]
-    if use_valgrind:
-        drop_in += [
-            'ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + networkd_bin,
-            f'ExecReload=valgrind {networkctl_bin} reload',
-            'PrivateTmp=yes'
+    create_service_dropin('systemd-networkd', networkd_bin,
+                          f'{networkctl_bin} reload',
+                          ['[Service]', 'Restart=no', '[Unit]', 'StartLimitIntervalSec=0'])
+    create_service_dropin('systemd-resolved', resolved_bin)
+    create_service_dropin('systemd-timesyncd', timesyncd_bin)
+
+    # TODO: also run udevd with sanitizers, valgrind, or coverage
+    #create_service_dropin('systemd-udevd', udevd_bin,
+    #                      f'{udevadm_bin} control --reload --timeout 0')
+    create_unit_dropin(
+        'systemd-udevd.service',
+        [
+            '[Service]',
+            'ExecStart=',
+            f'ExecStart=!!{udevd_bin}',
+            'ExecReload=',
+            f'ExecReload={udevadm_bin} control --reload --timeout 0',
         ]
-    else:
-        drop_in += [
-            'ExecStart=!!' + networkd_bin,
-            f'ExecReload={networkctl_bin} reload',
-        ]
-    if enable_debug:
-        drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
-    if asan_options:
-        drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
-    if lsan_options:
-        drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
-    if ubsan_options:
-        drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
-    if asan_options or lsan_options or ubsan_options:
-        drop_in += ['SystemCallFilter=']
-    if use_valgrind or asan_options or lsan_options or ubsan_options:
-        drop_in += ['MemoryDenyWriteExecute=no']
-    if with_coverage:
-        drop_in += [
-            'ProtectSystem=no',
-            'ProtectHome=no',
+    )
+    create_unit_dropin(
+        'systemd-networkd.socket',
+        [
+            '[Unit]',
+            'StartLimitIntervalSec=0',
         ]
-
-    mkdir_p('/run/systemd/system/systemd-networkd.service.d')
-    with open('/run/systemd/system/systemd-networkd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
-        f.write('\n'.join(drop_in))
-
-    drop_in = [
-        '[Service]',
-        'Restart=no',
-        'ExecStart=',
-    ]
-    if use_valgrind:
-        drop_in += ['ExecStart=!!valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ' + resolved_bin]
-    else:
-        drop_in += ['ExecStart=!!' + resolved_bin]
-    if enable_debug:
-        drop_in += ['Environment=SYSTEMD_LOG_LEVEL=debug']
-    if asan_options:
-        drop_in += ['Environment=ASAN_OPTIONS="' + asan_options + '"']
-    if lsan_options:
-        drop_in += ['Environment=LSAN_OPTIONS="' + lsan_options + '"']
-    if ubsan_options:
-        drop_in += ['Environment=UBSAN_OPTIONS="' + ubsan_options + '"']
-    if asan_options or lsan_options or ubsan_options:
-        drop_in += ['SystemCallFilter=']
-    if use_valgrind or asan_options or lsan_options or ubsan_options:
-        drop_in += ['MemoryDenyWriteExecute=no']
-    if with_coverage:
-        drop_in += [
-            'ProtectSystem=no',
-            'ProtectHome=no',
-        ]
-
-    mkdir_p('/run/systemd/system/systemd-resolved.service.d')
-    with open('/run/systemd/system/systemd-resolved.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
-        f.write('\n'.join(drop_in))
-
-    drop_in = [
-        '[Service]',
-        'ExecStart=',
-        'ExecStart=!!' + udevd_bin,
-    ]
-
-    mkdir_p('/run/systemd/system/systemd-udevd.service.d')
-    with open('/run/systemd/system/systemd-udevd.service.d/00-override.conf', mode='w', encoding='utf-8') as f:
-        f.write('\n'.join(drop_in))
+    )
 
     check_output('systemctl daemon-reload')
     print(check_output('systemctl cat systemd-networkd.service'))
     print(check_output('systemctl cat systemd-resolved.service'))
+    print(check_output('systemctl cat systemd-timesyncd.service'))
     print(check_output('systemctl cat systemd-udevd.service'))
     check_output('systemctl restart systemd-resolved.service')
+    check_output('systemctl restart systemd-timesyncd.service')
     check_output('systemctl restart systemd-udevd.service')
 
 def tearDownModule():
@@ -755,7 +718,9 @@ def tearDownModule():
     restore_timezone()
 
     rm_rf('/run/systemd/system/systemd-networkd.service.d')
+    rm_rf('/run/systemd/system/systemd-networkd.socket.d')
     rm_rf('/run/systemd/system/systemd-resolved.service.d')
+    rm_rf('/run/systemd/system/systemd-timesyncd.service.d')
     rm_rf('/run/systemd/system/systemd-udevd.service.d')
     check_output('systemctl daemon-reload')
     check_output('systemctl restart systemd-udevd.service')
@@ -886,7 +851,7 @@ class Utilities():
         try:
             check_output(*args, env=wait_online_env)
         except subprocess.CalledProcessError as e:
-            print(e.stdout) # show logs only on failure
+            # show detailed status on failure
             for link in links_with_operstate:
                 name = link.split(':')[0]
                 if link_exists(name):
@@ -1362,27 +1327,84 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'link/ether 12:34:56:78:9a:bf')
         self.assertRegex(output, 'mtu 1800')
 
-    def test_tun(self):
-        copy_network_unit('25-tun.netdev')
+    def test_tuntap(self):
+        copy_network_unit('25-tun.netdev', '25-tap.netdev', '26-netdev-link-local-addressing-yes.network')
         start_networkd()
 
-        self.wait_online(['tun99:off'], setup_state='unmanaged')
+        self.wait_online(['testtun99:degraded', 'testtap99:degraded'])
+
+        pid = networkd_pid()
+        name = psutil.Process(pid).name()[:15]
 
-        output = check_output('ip -d link show tun99')
+        output = check_output('ip -d tuntap show')
+        print(output)
+        self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+        self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+
+        output = check_output('ip -d link show testtun99')
         print(output)
         # Old ip command does not support IFF_ flags
         self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+        self.assertIn('UP,LOWER_UP', output)
 
-    def test_tap(self):
-        copy_network_unit('25-tap.netdev')
-        start_networkd()
+        output = check_output('ip -d link show testtap99')
+        print(output)
+        self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+        self.assertIn('UP,LOWER_UP', output)
 
-        self.wait_online(['tap99:off'], setup_state='unmanaged')
+        remove_network_unit('26-netdev-link-local-addressing-yes.network')
 
-        output = check_output('ip -d link show tap99')
+        restart_networkd()
+        self.wait_online(['testtun99:degraded', 'testtap99:degraded'], setup_state='unmanaged')
+
+        pid = networkd_pid()
+        name = psutil.Process(pid).name()[:15]
+
+        output = check_output('ip -d tuntap show')
+        print(output)
+        self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+        self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:{name}\({pid}\)systemd\(1\)$')
+
+        output = check_output('ip -d link show testtun99')
+        print(output)
+        self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+        self.assertIn('UP,LOWER_UP', output)
+
+        output = check_output('ip -d link show testtap99')
         print(output)
-        # Old ip command does not support IFF_ flags
         self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+        self.assertIn('UP,LOWER_UP', output)
+
+        clear_network_units()
+        restart_networkd()
+        self.wait_online(['testtun99:off', 'testtap99:off'], setup_state='unmanaged')
+
+        output = check_output('ip -d tuntap show')
+        print(output)
+        self.assertRegex(output, f'(?m)testtap99: tap pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
+        self.assertRegex(output, f'(?m)testtun99: tun pi (multi_queue |)vnet_hdr persist filter *(0x100|)\n\tAttached to processes:$')
+
+        for i in range(10):
+            if i != 0:
+                time.sleep(1)
+            output = check_output('ip -d link show testtun99')
+            print(output)
+            self.assertRegex(output, 'tun (type tun pi on vnet_hdr on multi_queue|addrgenmode) ')
+            if 'NO-CARRIER' in output:
+                break
+        else:
+            self.fail()
+
+        for i in range(10):
+            if i != 0:
+                time.sleep(1)
+            output = check_output('ip -d link show testtap99')
+            print(output)
+            self.assertRegex(output, 'tun (type tap pi on vnet_hdr on multi_queue|addrgenmode) ')
+            if 'NO-CARRIER' in output:
+                break
+        else:
+            self.fail()
 
     @expectedFailureIfModuleIsNotAvailable('vrf')
     def test_vrf(self):
@@ -2034,7 +2056,7 @@ class NetworkdL2TPTests(unittest.TestCase, Utilities):
     def tearDown(self):
         tear_down_common()
 
-    @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
+    @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_netlink')
     def test_l2tp_udp(self):
         copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
                           '25-l2tp-udp.netdev', '25-l2tp.network')
@@ -2062,7 +2084,7 @@ class NetworkdL2TPTests(unittest.TestCase, Utilities):
         self.assertRegex(output, "Peer session 18, tunnel 11")
         self.assertRegex(output, "interface name: l2tp-ses2")
 
-    @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
+    @expectedFailureIfModuleIsNotAvailable('l2tp_eth', 'l2tp_ip', 'l2tp_netlink')
     def test_l2tp_ip(self):
         copy_network_unit('11-dummy.netdev', '25-l2tp-dummy.network',
                           '25-l2tp-ip.netdev', '25-l2tp.network')
@@ -3281,59 +3303,146 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         print(output)
         self.assertEqual(output, '')
 
-    def test_qdisc(self):
-        copy_network_unit('25-qdisc-clsact-and-htb.network', '12-dummy.netdev',
-                          '25-qdisc-ingress-netem-compat.network', '11-dummy.netdev')
-        check_output('modprobe sch_teql max_equalizers=2')
+class NetworkdTCTests(unittest.TestCase, Utilities):
+
+    def setUp(self):
+        setup_common()
+
+    def tearDown(self):
+        tear_down_common()
+
+    @expectedFailureIfModuleIsNotAvailable('sch_cake')
+    def test_qdisc_cake(self):
+        copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
         start_networkd()
-        self.wait_online(['dummy98:routable', 'test1:routable'])
+        self.wait_online(['dummy98:routable'])
 
-        output = check_output('tc qdisc show dev test1')
+        output = check_output('tc qdisc show dev dummy98')
         print(output)
-        self.assertRegex(output, 'qdisc netem')
-        self.assertRegex(output, 'limit 100 delay 50(.0)?ms  10(.0)?ms loss 20%')
-        self.assertRegex(output, 'qdisc ingress')
+        self.assertIn('qdisc cake 3a: root', output)
+        self.assertIn('bandwidth 500Mbit', output)
+        self.assertIn('autorate-ingress', output)
+        self.assertIn('diffserv8', output)
+        self.assertIn('dual-dsthost', output)
+        self.assertIn(' nat', output)
+        self.assertIn(' wash', output)
+        self.assertIn(' split-gso', output)
+        self.assertIn(' raw', output)
+        self.assertIn(' atm', output)
+        self.assertIn('overhead 128', output)
+        self.assertIn('mpu 20', output)
+        self.assertIn('fwmark 0xff00', output)
+
+    @expectedFailureIfModuleIsNotAvailable('sch_codel')
+    def test_qdisc_codel(self):
+        copy_network_unit('25-qdisc-codel.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
-        self.assertRegex(output, 'qdisc clsact')
+        self.assertRegex(output, 'qdisc codel 33: root')
+        self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
 
-        self.assertRegex(output, 'qdisc htb 2: root')
-        self.assertRegex(output, r'default (0x30|30)')
+    @expectedFailureIfModuleIsNotAvailable('sch_drr')
+    def test_qdisc_drr(self):
+        copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
 
-        self.assertRegex(output, 'qdisc netem 30: parent 2:30')
-        self.assertRegex(output, 'limit 100 delay 50(.0)?ms  10(.0)?ms loss 20%')
-        self.assertRegex(output, 'qdisc fq_codel')
-        self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc drr 2: root')
+        output = check_output('tc class show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
 
-        self.assertRegex(output, 'qdisc teql1 31: parent 2:31')
+    @expectedFailureIfModuleIsNotAvailable('sch_ets')
+    def test_qdisc_ets(self):
+        copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
 
-        self.assertRegex(output, 'qdisc fq 32: parent 2:32')
+        self.assertRegex(output, 'qdisc ets 3a: root')
+        self.assertRegex(output, 'bands 10 strict 3')
+        self.assertRegex(output, 'quanta 1 2 3 4 5')
+        self.assertRegex(output, 'priomap 3 4 5 6 7')
+
+    @expectedFailureIfModuleIsNotAvailable('sch_fq')
+    def test_qdisc_fq(self):
+        copy_network_unit('25-qdisc-fq.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc fq 32: root')
         self.assertRegex(output, 'limit 1000p flow_limit 200p buckets 512 orphan_mask 511')
         self.assertRegex(output, 'quantum 1500')
         self.assertRegex(output, 'initial_quantum 13000')
         self.assertRegex(output, 'maxrate 1Mbit')
 
-        self.assertRegex(output, 'qdisc codel 33: parent 2:33')
-        self.assertRegex(output, 'limit 2000p target 10(.0)?ms ce_threshold 100(.0)?ms interval 50(.0)?ms ecn')
+    @expectedFailureIfModuleIsNotAvailable('sch_fq_codel')
+    def test_qdisc_fq_codel(self):
+        copy_network_unit('25-qdisc-fq_codel.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
 
-        self.assertRegex(output, 'qdisc fq_codel 34: parent 2:34')
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc fq_codel 34: root')
         self.assertRegex(output, 'limit 20480p flows 2048 quantum 1400 target 10(.0)?ms ce_threshold 100(.0)?ms interval 200(.0)?ms memory_limit 64Mb ecn')
 
-        self.assertRegex(output, 'qdisc tbf 35: parent 2:35')
-        self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
+    @expectedFailureIfModuleIsNotAvailable('sch_fq_pie')
+    def test_qdisc_fq_pie(self):
+        copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
 
-        self.assertRegex(output, 'qdisc sfq 36: parent 2:36')
-        self.assertRegex(output, 'perturb 5sec')
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
 
-        self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
-        self.assertRegex(output, 'limit 100000p')
+        self.assertRegex(output, 'qdisc fq_pie 3a: root')
+        self.assertRegex(output, 'limit 200000p')
 
-        self.assertRegex(output, 'qdisc gred 38: parent 2:38')
+    @expectedFailureIfModuleIsNotAvailable('sch_gred')
+    def test_qdisc_gred(self):
+        copy_network_unit('25-qdisc-gred.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc gred 38: root')
         self.assertRegex(output, 'vqs 12 default 10 grio')
 
-        self.assertRegex(output, 'qdisc sfb 39: parent 2:39')
-        self.assertRegex(output, 'limit 200000')
+    @expectedFailureIfModuleIsNotAvailable('sch_hhf')
+    def test_qdisc_hhf(self):
+        copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc hhf 3a: root')
+        self.assertRegex(output, 'limit 1022p')
+
+    @expectedFailureIfModuleIsNotAvailable('sch_htb')
+    def test_qdisc_htb_fifo(self):
+        copy_network_unit('25-qdisc-htb-fifo.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc htb 2: root')
+        self.assertRegex(output, r'default (0x30|30)')
+
+        self.assertRegex(output, 'qdisc pfifo 37: parent 2:37')
+        self.assertRegex(output, 'limit 100000p')
 
         self.assertRegex(output, 'qdisc bfifo 3a: parent 2:3a')
         self.assertRegex(output, 'limit 1000000')
@@ -3345,16 +3454,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
 
         output = check_output('tc -d class show dev dummy98')
         print(output)
-        self.assertRegex(output, 'class htb 2:30 root leaf 30:')
-        self.assertRegex(output, 'class htb 2:31 root leaf 31:')
-        self.assertRegex(output, 'class htb 2:32 root leaf 32:')
-        self.assertRegex(output, 'class htb 2:33 root leaf 33:')
-        self.assertRegex(output, 'class htb 2:34 root leaf 34:')
-        self.assertRegex(output, 'class htb 2:35 root leaf 35:')
-        self.assertRegex(output, 'class htb 2:36 root leaf 36:')
         self.assertRegex(output, 'class htb 2:37 root leaf 37:')
-        self.assertRegex(output, 'class htb 2:38 root leaf 38:')
-        self.assertRegex(output, 'class htb 2:39 root leaf 39:')
         self.assertRegex(output, 'class htb 2:3a root leaf 3a:')
         self.assertRegex(output, 'class htb 2:3b root leaf 3b:')
         self.assertRegex(output, 'class htb 2:3c root leaf 3c:')
@@ -3362,50 +3462,39 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'burst 123456')
         self.assertRegex(output, 'cburst 123457')
 
-    def test_qdisc2(self):
-        copy_network_unit('25-qdisc-drr.network', '12-dummy.netdev',
-                          '25-qdisc-qfq.network', '11-dummy.netdev')
+    @expectedFailureIfModuleIsNotAvailable('sch_ingress')
+    def test_qdisc_ingress(self):
+        copy_network_unit('25-qdisc-clsact.network', '12-dummy.netdev',
+                          '25-qdisc-ingress.network', '11-dummy.netdev')
         start_networkd()
         self.wait_online(['dummy98:routable', 'test1:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
-        self.assertRegex(output, 'qdisc drr 2: root')
-        output = check_output('tc class show dev dummy98')
-        print(output)
-        self.assertRegex(output, 'class drr 2:30 root quantum 2000b')
+        self.assertRegex(output, 'qdisc clsact')
 
         output = check_output('tc qdisc show dev test1')
         print(output)
-        self.assertRegex(output, 'qdisc qfq 2: root')
-        output = check_output('tc class show dev test1')
-        print(output)
-        self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
-        self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
+        self.assertRegex(output, 'qdisc ingress')
 
-    @expectedFailureIfCAKEIsNotAvailable()
-    def test_qdisc_cake(self):
-        copy_network_unit('25-qdisc-cake.network', '12-dummy.netdev')
+    @expectedFailureIfModuleIsNotAvailable('sch_netem')
+    def test_qdisc_netem(self):
+        copy_network_unit('25-qdisc-netem.network', '12-dummy.netdev',
+                          '25-qdisc-netem-compat.network', '11-dummy.netdev')
         start_networkd()
-        self.wait_online(['dummy98:routable'])
+        self.wait_online(['dummy98:routable', 'test1:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
-        self.assertIn('qdisc cake 3a: root', output)
-        self.assertIn('bandwidth 500Mbit', output)
-        self.assertIn('autorate-ingress', output)
-        self.assertIn('diffserv8', output)
-        self.assertIn('dual-dsthost', output)
-        self.assertIn(' nat', output)
-        self.assertIn(' wash', output)
-        self.assertIn(' split-gso', output)
-        self.assertIn(' raw', output)
-        self.assertIn(' atm', output)
-        self.assertIn('overhead 128', output)
-        self.assertIn('mpu 20', output)
-        self.assertIn('fwmark 0xff00', output)
+        self.assertRegex(output, 'qdisc netem 30: root')
+        self.assertRegex(output, 'limit 100 delay 50(.0)?ms  10(.0)?ms loss 20%')
 
-    @expectedFailureIfPIEIsNotAvailable()
+        output = check_output('tc qdisc show dev test1')
+        print(output)
+        self.assertRegex(output, 'qdisc netem [0-9a-f]*: root')
+        self.assertRegex(output, 'limit 100 delay 50(.0)?ms  10(.0)?ms loss 20%')
+
+    @expectedFailureIfModuleIsNotAvailable('sch_pie')
     def test_qdisc_pie(self):
         copy_network_unit('25-qdisc-pie.network', '12-dummy.netdev')
         start_networkd()
@@ -3416,43 +3505,76 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'qdisc pie 3a: root')
         self.assertRegex(output, 'limit 200000')
 
-    @expectedFailureIfHHFIsNotAvailable()
-    def test_qdisc_hhf(self):
-        copy_network_unit('25-qdisc-hhf.network', '12-dummy.netdev')
+    @expectedFailureIfModuleIsNotAvailable('sch_qfq')
+    def test_qdisc_qfq(self):
+        copy_network_unit('25-qdisc-qfq.network', '12-dummy.netdev')
         start_networkd()
         self.wait_online(['dummy98:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
-        self.assertRegex(output, 'qdisc hhf 3a: root')
-        self.assertRegex(output, 'limit 1022p')
+        self.assertRegex(output, 'qdisc qfq 2: root')
+        output = check_output('tc class show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'class qfq 2:30 root weight 2 maxpkt 16000')
+        self.assertRegex(output, 'class qfq 2:31 root weight 10 maxpkt 8000')
 
-    @expectedFailureIfETSIsNotAvailable()
-    def test_qdisc_ets(self):
-        copy_network_unit('25-qdisc-ets.network', '12-dummy.netdev')
+    @expectedFailureIfModuleIsNotAvailable('sch_sfb')
+    def test_qdisc_sfb(self):
+        copy_network_unit('25-qdisc-sfb.network', '12-dummy.netdev')
         start_networkd()
         self.wait_online(['dummy98:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
+        self.assertRegex(output, 'qdisc sfb 39: root')
+        self.assertRegex(output, 'limit 200000')
 
-        self.assertRegex(output, 'qdisc ets 3a: root')
-        self.assertRegex(output, 'bands 10 strict 3')
-        self.assertRegex(output, 'quanta 1 2 3 4 5')
-        self.assertRegex(output, 'priomap 3 4 5 6 7')
+    @expectedFailureIfModuleIsNotAvailable('sch_sfq')
+    def test_qdisc_sfq(self):
+        copy_network_unit('25-qdisc-sfq.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_online(['dummy98:routable'])
 
-    @expectedFailureIfFQPIEIsNotAvailable()
-    def test_qdisc_fq_pie(self):
-        copy_network_unit('25-qdisc-fq_pie.network', '12-dummy.netdev')
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc sfq 36: root')
+        self.assertRegex(output, 'perturb 5sec')
+
+    @expectedFailureIfModuleIsNotAvailable('sch_tbf')
+    def test_qdisc_tbf(self):
+        copy_network_unit('25-qdisc-tbf.network', '12-dummy.netdev')
         start_networkd()
         self.wait_online(['dummy98:routable'])
 
         output = check_output('tc qdisc show dev dummy98')
         print(output)
+        self.assertRegex(output, 'qdisc tbf 35: root')
+        self.assertRegex(output, 'rate 1Gbit burst 5000b peakrate 100Gbit minburst 987500b lat 70(.0)?ms')
 
-        self.assertRegex(output, 'qdisc fq_pie 3a: root')
-        self.assertRegex(output, 'limit 200000p')
+    @expectedFailureIfModuleIsNotAvailable('sch_teql')
+    def test_qdisc_teql(self):
+        call_quiet('rmmod sch_teql')
+
+        copy_network_unit('25-qdisc-teql.network', '12-dummy.netdev')
+        start_networkd()
+        self.wait_links('dummy98')
+        check_output('modprobe sch_teql max_equalizers=2')
+        self.wait_online(['dummy98:routable'])
+
+        output = check_output('tc qdisc show dev dummy98')
+        print(output)
+        self.assertRegex(output, 'qdisc teql1 31: root')
+
+class NetworkWaitOnlineTests(unittest.TestCase, Utilities):
+
+    def setUp(self):
+        setup_common()
+
+    def tearDown(self):
+        tear_down_common()
 
+    @expectedFailureIfModuleIsNotAvailable('sch_netem')
     def test_wait_online_ipv4(self):
         copy_network_unit('25-veth.netdev', '25-dhcp-server-with-ipv6-prefix.network', '25-dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
         start_networkd()
@@ -3461,6 +3583,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
 
         self.wait_address('veth99', r'192.168.5.[0-9]+', ipv='-4', timeout_sec=1)
 
+    @expectedFailureIfModuleIsNotAvailable('sch_netem')
     def test_wait_online_ipv6(self):
         copy_network_unit('25-veth.netdev', '25-ipv6-prefix-with-delay.network', '25-ipv6ra-prefix-client-with-static-ipv4-address.network')
         start_networkd()
@@ -3735,8 +3858,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress',       '1', allow_enoent=True)
         self.check_bridge_port_attr('bridge99', 'dummy98', 'learning',             '0')
         self.check_bridge_port_attr('bridge99', 'dummy98', 'priority',             '23')
-        self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard',           '1')
-        self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block',           '1')
+        self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard',           '0')
+        self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block',           '0')
 
     def test_bridge_property(self):
         copy_network_unit('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
@@ -3745,19 +3868,25 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         start_networkd()
         self.wait_online(['dummy98:enslaved', 'test1:enslaved', 'bridge99:routable'])
 
+        output = check_output('ip -d link show bridge99')
+        print(output)
+        self.assertIn('mtu 9000 ', output)
+
         output = check_output('ip -d link show test1')
         print(output)
-        self.assertRegex(output, 'master')
-        self.assertRegex(output, 'bridge')
+        self.assertIn('master bridge99 ', output)
+        self.assertIn('bridge_slave', output)
+        self.assertIn('mtu 9000 ', output)
 
         output = check_output('ip -d link show dummy98')
         print(output)
-        self.assertRegex(output, 'master')
-        self.assertRegex(output, 'bridge')
+        self.assertIn('master bridge99 ', output)
+        self.assertIn('bridge_slave', output)
+        self.assertIn('mtu 9000 ', output)
 
         output = check_output('ip addr show bridge99')
         print(output)
-        self.assertRegex(output, '192.168.0.15/24')
+        self.assertIn('192.168.0.15/24', output)
 
         output = check_output('bridge -d link show dummy98')
         print(output)
@@ -3772,8 +3901,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         self.check_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress',       '1', allow_enoent=True)
         self.check_bridge_port_attr('bridge99', 'dummy98', 'learning',             '0')
         self.check_bridge_port_attr('bridge99', 'dummy98', 'priority',             '23')
-        self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard',           '1')
-        self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block',           '1')
+        self.check_bridge_port_attr('bridge99', 'dummy98', 'bpdu_guard',           '0')
+        self.check_bridge_port_attr('bridge99', 'dummy98', 'root_block',           '0')
 
         output = check_output('bridge -d link show test1')
         print(output)
@@ -3782,7 +3911,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         check_output('ip address add 192.168.0.16/24 dev bridge99')
         output = check_output('ip addr show bridge99')
         print(output)
-        self.assertRegex(output, '192.168.0.16/24')
+        self.assertIn('192.168.0.16/24', output)
 
         # for issue #6088
         print('### ip -6 route list table all dev bridge99')
@@ -3791,24 +3920,49 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
 
         remove_link('test1')
-
         self.wait_operstate('bridge99', 'degraded-carrier')
 
-        remove_link('dummy98')
+        output = check_output('ip -d link show bridge99')
+        print(output)
+        self.assertIn('mtu 9000 ', output)
+
+        output = check_output('ip -d link show dummy98')
+        print(output)
+        self.assertIn('master bridge99 ', output)
+        self.assertIn('bridge_slave', output)
+        self.assertIn('mtu 9000 ', output)
 
+        remove_link('dummy98')
         self.wait_operstate('bridge99', 'no-carrier')
 
+        output = check_output('ip -d link show bridge99')
+        print(output)
+        # When no carrier, the kernel may reset the MTU
+        self.assertIn('NO-CARRIER', output)
+
         output = check_output('ip address show bridge99')
         print(output)
-        self.assertRegex(output, 'NO-CARRIER')
-        self.assertNotRegex(output, '192.168.0.15/24')
-        self.assertRegex(output, '192.168.0.16/24') # foreign address is kept
+        self.assertNotIn('192.168.0.15/24', output)
+        self.assertIn('192.168.0.16/24', output) # foreign address is kept
 
         print('### ip -6 route list table all dev bridge99')
         output = check_output('ip -6 route list table all dev bridge99')
         print(output)
         self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium')
 
+        check_output('ip link add dummy98 type dummy')
+        self.wait_online(['dummy98:enslaved', 'bridge99:routable'])
+
+        output = check_output('ip -d link show bridge99')
+        print(output)
+        self.assertIn('mtu 9000 ', output)
+
+        output = check_output('ip -d link show dummy98')
+        print(output)
+        self.assertIn('master bridge99 ', output)
+        self.assertIn('bridge_slave', output)
+        self.assertIn('mtu 9000 ', output)
+
     def test_bridge_configure_without_carrier(self):
         copy_network_unit('26-bridge.netdev', '26-bridge-configure-without-carrier.network',
                           '11-dummy.netdev')
@@ -3952,7 +4106,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
 
         udev_reload()
-        call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+        call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
 
         output = check_output('ip link show dev eni99np1')
         print(output)
@@ -3968,7 +4122,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             f.write('[Link]\nSR-IOVVirtualFunctions=\n')
 
         udev_reload()
-        call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+        call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
 
         output = check_output('ip link show dev eni99np1')
         print(output)
@@ -3984,7 +4138,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
 
         udev_reload()
-        call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+        call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
 
         output = check_output('ip link show dev eni99np1')
         print(output)
@@ -4000,7 +4154,7 @@ class NetworkdSRIOVTests(unittest.TestCase, Utilities):
             f.write('[Link]\nSR-IOVVirtualFunctions=\n')
 
         udev_reload()
-        call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+        call(*udevadm_cmd, 'trigger', '--action=add', '--settle', '/sys/devices/netdevsim99/net/eni99np1')
 
         output = check_output('ip link show dev eni99np1')
         print(output)
@@ -5135,7 +5289,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
 
         self.verify_dhcp4_6rd(tunnel_name)
 
-        print('Wait for the DHCP lease to be expired')
+        print('Wait for the DHCP lease to be renewed/rebind')
         time.sleep(120)
 
         self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
@@ -5307,11 +5461,13 @@ if __name__ == '__main__':
     parser.add_argument('--build-dir', help='Path to build dir', dest='build_dir')
     parser.add_argument('--networkd', help='Path to systemd-networkd', dest='networkd_bin')
     parser.add_argument('--resolved', help='Path to systemd-resolved', dest='resolved_bin')
+    parser.add_argument('--timesyncd', help='Path to systemd-timesyncd', dest='timesyncd_bin')
     parser.add_argument('--udevd', help='Path to systemd-udevd', dest='udevd_bin')
     parser.add_argument('--wait-online', help='Path to systemd-networkd-wait-online', dest='wait_online_bin')
     parser.add_argument('--networkctl', help='Path to networkctl', dest='networkctl_bin')
     parser.add_argument('--resolvectl', help='Path to resolvectl', dest='resolvectl_bin')
     parser.add_argument('--timedatectl', help='Path to timedatectl', dest='timedatectl_bin')
+    parser.add_argument('--udevadm', help='Path to udevadm', dest='udevadm_bin')
     parser.add_argument('--valgrind', help='Enable valgrind', dest='use_valgrind', type=bool, nargs='?', const=True, default=use_valgrind)
     parser.add_argument('--debug', help='Generate debugging logs', dest='enable_debug', type=bool, nargs='?', const=True, default=enable_debug)
     parser.add_argument('--asan-options', help='ASAN options', dest='asan_options')
@@ -5321,20 +5477,25 @@ if __name__ == '__main__':
     ns, unknown_args = parser.parse_known_args(namespace=unittest)
 
     if ns.build_dir:
-        if ns.networkd_bin or ns.resolved_bin or ns.udevd_bin or ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin:
-            print('WARNING: --networkd, --resolved, --wait-online, --networkctl, --resolvectl, or --timedatectl options are ignored when --build-dir is specified.')
+        if ns.networkd_bin or ns.resolved_bin or ns.timesyncd_bin or ns.udevd_bin or \
+           ns.wait_online_bin or ns.networkctl_bin or ns.resolvectl_bin or ns.timedatectl_bin or ns.udevadm_bin:
+            print('WARNING: --networkd, --resolved, --timesyncd, --udevd, --wait-online, --networkctl, --resolvectl, --timedatectl, or --udevadm options are ignored when --build-dir is specified.')
         networkd_bin = os.path.join(ns.build_dir, 'systemd-networkd')
         resolved_bin = os.path.join(ns.build_dir, 'systemd-resolved')
+        timesyncd_bin = os.path.join(ns.build_dir, 'systemd-timesyncd')
         udevd_bin = os.path.join(ns.build_dir, 'systemd-udevd')
         wait_online_bin = os.path.join(ns.build_dir, 'systemd-networkd-wait-online')
         networkctl_bin = os.path.join(ns.build_dir, 'networkctl')
         resolvectl_bin = os.path.join(ns.build_dir, 'resolvectl')
         timedatectl_bin = os.path.join(ns.build_dir, 'timedatectl')
+        udevadm_bin = os.path.join(ns.build_dir, 'udevadm')
     else:
         if ns.networkd_bin:
             networkd_bin = ns.networkd_bin
         if ns.resolved_bin:
             resolved_bin = ns.resolved_bin
+        if ns.timesyncd_bin:
+            timesyncd_bin = ns.timesyncd_bin
         if ns.udevd_bin:
             udevd_bin = ns.udevd_bin
         if ns.wait_online_bin:
@@ -5345,6 +5506,8 @@ if __name__ == '__main__':
             resolvectl_bin = ns.resolvectl_bin
         if ns.timedatectl_bin:
             timedatectl_bin = ns.timedatectl_bin
+        if ns.udevadm_bin:
+            udevadm_bin = ns.udevadm_bin
 
     use_valgrind = ns.use_valgrind
     enable_debug = ns.enable_debug
@@ -5354,15 +5517,14 @@ if __name__ == '__main__':
     with_coverage = ns.with_coverage
 
     if use_valgrind:
-        networkctl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', networkctl_bin]
-        resolvectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', resolvectl_bin]
-        timedatectl_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', timedatectl_bin]
-        wait_online_cmd = ['valgrind', '--track-origins=yes', '--leak-check=full', '--show-leak-kinds=all', wait_online_bin]
-    else:
-        networkctl_cmd = [networkctl_bin]
-        resolvectl_cmd = [resolvectl_bin]
-        timedatectl_cmd = [timedatectl_bin]
-        wait_online_cmd = [wait_online_bin]
+        # Do not forget the trailing space.
+        valgrind_cmd = 'valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all '
+
+    networkctl_cmd = valgrind_cmd.split() + [networkctl_bin]
+    resolvectl_cmd = valgrind_cmd.split() + [resolvectl_bin]
+    timedatectl_cmd = valgrind_cmd.split() + [timedatectl_bin]
+    udevadm_cmd = valgrind_cmd.split() + [udevadm_bin]
+    wait_online_cmd = valgrind_cmd.split() + [wait_online_bin]
 
     if asan_options:
         env.update({'ASAN_OPTIONS': asan_options})
@@ -5370,6 +5532,8 @@ if __name__ == '__main__':
         env.update({'LSAN_OPTIONS': lsan_options})
     if ubsan_options:
         env.update({'UBSAN_OPTIONS': ubsan_options})
+    if use_valgrind:
+        env.update({'SYSTEMD_MEMPOOL': '0'})
 
     wait_online_env = env.copy()
     if enable_debug:
index 66357ab688bf5c36062ba078ba1558bc78f5d695..2f4d93ab8cd11b7cb896cda8abaaab440728c48f 100644 (file)
@@ -4,10 +4,10 @@
 # utility functions for shell tests
 
 assert_true() {(
-    local rc
-
     set +ex
 
+    local rc
+
     "$@"
     rc=$?
     if [[ $rc -ne 0 ]]; then
@@ -47,10 +47,10 @@ assert_not_in() {(
 )}
 
 assert_rc() {(
-    local rc exp="${1?}"
-
     set +ex
 
+    local rc exp="${1?}"
+
     shift
     "$@"
     rc=$?
diff --git a/test/units/testsuite-17.07.sh b/test/units/testsuite-17.07.sh
new file mode 100755 (executable)
index 0000000..549107a
--- /dev/null
@@ -0,0 +1,205 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
+wait_service_active() {(
+    set +ex
+    for (( i = 0; i < 20; i++ )); do
+        if (( i != 0 )); then sleep 0.5; fi
+        if systemctl --quiet is-active "${1?}"; then
+            return 0
+        fi
+    done
+    return 1
+)}
+
+wait_service_inactive() {(
+    set +ex
+    for (( i = 0; i < 20; i++ )); do
+        if (( i != 0 )); then sleep 0.5; fi
+        systemctl --quiet is-active "${1?}"
+        if [[ "$?" == "3" ]]; then
+            return 0
+        fi
+    done
+    return 1
+)}
+
+mkdir -p /run/systemd/system
+cat >/run/systemd/system/both.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+cat >/run/systemd/system/on-add.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+cat >/run/systemd/system/on-change.service <<EOF
+[Service]
+ExecStart=sleep 1000
+EOF
+
+systemctl daemon-reload
+
+mkdir -p /run/udev/rules.d/
+cat >/run/udev/rules.d/50-testsuite.rules <<EOF
+SUBSYSTEM=="net", KERNEL=="dummy9?", OPTIONS="log_level=debug"
+SUBSYSTEM=="net", KERNEL=="dummy9?", ACTION=="add",    TAG+="systemd", ENV{SYSTEMD_WANTS}+="both.service", ENV{SYSTEMD_WANTS}+="on-add.service"
+SUBSYSTEM=="net", KERNEL=="dummy9?", ACTION=="change", TAG+="systemd", ENV{SYSTEMD_WANTS}+="both.service", ENV{SYSTEMD_WANTS}+="on-change.service"
+EOF
+
+udevadm control --reload
+
+# StopWhenUnneeded=no
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+systemctl stop both.service on-add.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+udevadm info /sys/class/net/dummy99
+wait_service_active both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_active on-change.service
+systemctl stop both.service on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+assert_rc 3 systemctl --quiet is-active both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes
+cat >/run/systemd/system/both.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=sleep 1000
+Type=simple
+EOF
+
+cat >/run/systemd/system/on-add.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=sleep 1000
+Type=simple
+EOF
+
+cat >/run/systemd/system/on-change.service <<EOF
+[Unit]
+StopWhenUnneeded=yes
+
+[Service]
+ExecStart=echo changed
+RemainAfterExit=true
+Type=oneshot
+EOF
+
+systemctl daemon-reload
+
+# StopWhenUnneeded=yes (single device, only add event)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+wait_service_inactive on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes (single device, add and change event)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+wait_service_inactive on-add.service
+wait_service_active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_inactive on-change.service
+
+# StopWhenUnneeded=yes (multiple devices, only add events)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link add dummy98 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link del dummy98
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy98
+wait_service_inactive both.service
+wait_service_inactive on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+# StopWhenUnneeded=yes (multiple devices, add and change events)
+ip link add dummy99 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy99
+wait_service_active both.service
+wait_service_active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+ip link add dummy98 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+assert_rc 3 systemctl --quiet is-active on-change.service
+
+udevadm trigger --action=change --settle /sys/class/net/dummy99
+assert_rc 0 systemctl --quiet is-active both.service
+assert_rc 0 systemctl --quiet is-active on-add.service
+wait_service_active on-change.service
+
+ip link del dummy98
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy98
+assert_rc 0 systemctl --quiet is-active both.service
+wait_service_inactive on-add.service
+assert_rc 0 systemctl --quiet is-active on-change.service
+
+ip link del dummy99
+udevadm wait --settle --timeout=30 --removed /sys/class/net/dummy99
+wait_service_inactive both.service
+assert_rc 3 systemctl --quiet is-active on-add.service
+wait_service_inactive on-change.service
+
+# cleanup
+rm -f /run/udev/rules.d/50-testsuite.rules
+udevadm control --reload
+
+rm -f /run/systemd/system/on-add.service
+rm -f /run/systemd/system/on-change.service
+systemctl daemon-reload
+
+exit 0
index 31cb52064eaa149a6228856899cb1e8c677b1c4d..f2d937daba3a5f8e6776e26da177f234115012db 100755 (executable)
@@ -285,7 +285,7 @@ Type=notify
 RemainAfterExit=yes
 MountAPIVFS=yes
 PrivateTmp=yes
-ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do sleep 0.1; done; mount | grep -F "/dev/mapper/${roothash}-verity" | grep -q -F "nosuid"'
+ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do sleep 0.1; done; mount | grep -e "/dev/mapper/${roothash}-verity" -e "/dev/mapper/loop[0-9]*-verity" | grep -q -F "nosuid"'
 EOF
 systemctl start testservice-50d.service
 
@@ -305,6 +305,7 @@ systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.r
 systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
 systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
 systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
+systemd-run -P --property ExtensionImages=/usr/share/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
 cat >/run/systemd/system/testservice-50e.service <<EOF
 [Service]
 MountAPIVFS=yes
@@ -323,17 +324,19 @@ systemctl start testservice-50e.service
 systemctl is-active testservice-50e.service
 
 # ExtensionDirectories will set up an overlay
-mkdir -p "${image_dir}/app0" "${image_dir}/app1"
+mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro"
 systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
 systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0"
 systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1"
+systemd-dissect --mount /usr/share/app-nodistro.raw "${image_dir}/app-nodistro"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
 systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
+systemd-run -P --property ExtensionDirectories="${image_dir}/app-nodistro" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
 cat >/run/systemd/system/testservice-50f.service <<EOF
 [Service]
 MountAPIVFS=yes
@@ -353,6 +356,19 @@ systemctl is-active testservice-50f.service
 systemd-dissect --umount "${image_dir}/app0"
 systemd-dissect --umount "${image_dir}/app1"
 
+# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence
+mkdir -p /var/lib/extensions/
+ln -s /usr/share/app-nodistro.raw /var/lib/extensions/app-nodistro.raw
+systemd-sysext merge
+grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
+systemd-sysext unmerge
+mkdir -p /etc/extensions/app-nodistro
+systemd-sysext merge
+test ! -e /usr/lib/systemd/system/some_file
+systemd-sysext unmerge
+rmdir /etc/extensions/app-nodistro
+rm /var/lib/extensions/app-nodistro.raw
+
 echo OK >/testok
 
 exit 0
index 84cd66129d007e40c166bf8b772e26161a5a7b14..f12b7379fdb2720b073ded257371a7b008641a38 100755 (executable)
@@ -5,27 +5,44 @@ set -o pipefail
 
 : >/failed
 
+# Run a timer for every 15 minutes before setting the current time
+systemd-run --unit test-timer-1 --on-calendar "*:0/15:0" true
+
 # Reset host date to current time, 3 days in the past.
 date -s "-3 days"
 
-# Run a timer for every 15 minutes.
-systemd-run --unit test-timer --on-calendar "*:0/15:0" true
+# Run another timer for every 15 minutes, after setting the time
+systemd-run --unit test-timer-2 --on-calendar "*:0/15:0" true
+
+next_elapsed_t1=$(systemctl show test-timer-1.timer -p NextElapseUSecRealtime --value)
+next_elapsed_t1=$(date -d "${next_elapsed_t1}" +%s)
+now=$(date +%s)
+time_delta_t1=$((next_elapsed_t1 - now))
 
-next_elapsed=$(systemctl show test-timer.timer -p NextElapseUSecRealtime --value)
-next_elapsed=$(date -d "${next_elapsed}" +%s)
+next_elapsed_t2=$(systemctl show test-timer-2.timer -p NextElapseUSecRealtime --value)
+next_elapsed_t2=$(date -d "${next_elapsed_t2}" +%s)
 now=$(date +%s)
-time_delta=$((next_elapsed - now))
+time_delta_t2=$((next_elapsed_t2 - now))
+
+# Check that the timer will elapse in less than 20 minutes.
+((0 < time_delta_t1 && time_delta_t1 < 1200)) || {
+    echo 'Timer elapse outside of the expected 20 minute window.'
+    echo "  next_elapsed_t1=${next_elapsed_t1}"
+    echo "  now=${now}"
+    echo "  time_delta_t1=${time_delta_t1}"
+    echo ''
+} >>/failed_t1
 
 # Check that the timer will elapse in less than 20 minutes.
-((0 < time_delta && time_delta < 1200)) || {
+((0 < time_delta_t2 && time_delta_t2 < 1200)) || {
     echo 'Timer elapse outside of the expected 20 minute window.'
-    echo "  next_elapsed=${next_elapsed}"
+    echo "  next_elapsed_t2=${next_elapsed_t2}"
     echo "  now=${now}"
-    echo "  time_delta=${time_delta}"
+    echo "  time_delta_t2=${time_delta_t2}"
     echo ''
-} >>/failed
+} >>/failed_t2
 
-if test ! -s /failed ; then
-    rm -f /failed
+if test ! -s /failed_t1 && test ! -s /failed_t2; then
+    rm -f /failed_t*
     touch /testok
 fi
index 877359f4b0960d337d7b6a613632c41ba16afd72..258f39c38d0a5dceaa63299feafa3b4a4113b6d3 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 # SPDX-License-Identifier: LGPL-2.1-or-later
 set -ex
+set -o pipefail
 
 export SYSTEMD_LOG_LEVEL=debug
 
@@ -11,6 +12,9 @@ dd if=/dev/zero of=$img bs=1024k count=20 status=none
 echo -n passphrase >/tmp/passphrase
 cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img /tmp/passphrase
 
+# Unlocking via keyfile
+systemd-cryptenroll --unlock-key-file=/tmp/passphrase --tpm2-device=auto $img
+
 # Enroll unlock with default PCR policy
 env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img
 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1
@@ -29,6 +33,17 @@ env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm
 # Check failure with wrong PIN
 env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
 
+# Check LUKS2 token plugin unlock (i.e. without specifying tpm2-device=auto)
+if cryptsetup --help | grep -q 'LUKS2 external token plugin support is compiled-in'; then
+    env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1
+    /usr/lib/systemd/systemd-cryptsetup detach test-volume
+
+    # Check failure with wrong PIN
+    env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 && { echo 'unexpected success'; exit 1; }
+else
+    echo 'cryptsetup has no LUKS2 token plugin support, skipping'
+fi
+
 # Check failure with wrong PCR (and correct PIN)
 tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000
 env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; }
@@ -43,18 +58,18 @@ env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $
 tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000
 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1
 
-if [[ -e /usr/lib/systemd/sytemd-measure ]]; then
+if [[ -e /usr/lib/systemd/systemd-measure ]]; then
     echo HALLO > /tmp/tpmdata1
     echo foobar > /tmp/tpmdata2
 
     cat >/tmp/result <<EOF
-    11:sha1=5177e4ad69db92192c10e5f80402bf81bfec8a81
-    11:sha256=37b48bd0b222394dbe3cceff2fca4660c4b0a90ae9369ec90b42f14489989c13
-    11:sha384=5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087
-    11:sha512=961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b
+11:sha1=5177e4ad69db92192c10e5f80402bf81bfec8a81
+11:sha256=37b48bd0b222394dbe3cceff2fca4660c4b0a90ae9369ec90b42f14489989c13
+11:sha384=5573f9b2caf55b1d0a6a701f890662d682af961899f0419cf1e2d5ea4a6a68c1f25bd4f5b8a0865eeee82af90f5cb087
+11:sha512=961305d7e9981d6606d1ce97b3a9a1f92610cac033e9c39064895f0e306abc1680463d55767bd98e751eae115bdef3675a9ee1d29ed37da7885b1db45bb2555b
 EOF
 
-    /usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 | cmp - /tmp/result
+    /usr/lib/systemd/systemd-measure calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 | cmp - /tmp/result
 else
     echo "/usr/lib/systemd/systemd-measure not found, skipping the test case"
 fi
index 6ebdbc6a54901097eb2d30bad3a234c211905f5f..cb571f8b97764396366e17bbae93629d6fa4c155 100755 (executable)
@@ -3,14 +3,37 @@
 set -eux
 set -o pipefail
 
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
 export SYSTEMD_LOG_LEVEL=debug
 
-echo "foo.bar=42" > /etc/sysctl.d/foo.conf
-[[ $(/usr/lib/systemd/systemd-sysctl /etc/sysctl.d/foo.conf)$? -eq 0 ]]
-[[ $(/usr/lib/systemd/systemd-sysctl --strict /etc/sysctl.d/foo.conf)$? -ne 0 ]]
+echo "foo.bar=42" > /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf
+assert_rc 1 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf
+
+echo "-foo.foo=42" > /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl /tmp/foo.conf
+assert_rc 0 /usr/lib/systemd/systemd-sysctl --strict /tmp/foo.conf
+
+if ! systemd-detect-virt --quiet --container; then
+    ip link add hoge type dummy
+    udevadm wait /sys/class/net/hoge
+
+    cat >/tmp/foo.conf <<EOF
+net.ipv4.conf.*.drop_gratuitous_arp=1
+net.ipv4.*.*.bootp_relay=1
+net.ipv4.aaa.*.disable_policy=1
+EOF
+
+    echo 0 > /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp
+    echo 0 > /proc/sys/net/ipv4/conf/hoge/bootp_relay
+    echo 0 > /proc/sys/net/ipv4/conf/hoge/disable_policy
 
-echo "-foo.foo=42" > /etc/sysctl.d/foo.conf
-[[ $(/usr/lib/systemd/systemd-sysctl /etc/sysctl.d/foo.conf)$? -eq 0 ]]
-[[ $(/usr/lib/systemd/systemd-sysctl --strict /etc/sysctl.d/foo.conf)$? -eq 0 ]]
+    assert_rc 0 /usr/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/hoge /tmp/foo.conf
+    assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/drop_gratuitous_arp)" "1"
+    assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/bootp_relay)" "1"
+    assert_eq "$(cat /proc/sys/net/ipv4/conf/hoge/disable_policy)" "0"
+fi
 
 touch /testok
index f140b7817406b798b371f1b19774466dbeecf3e5..361376fd21e3ecb6a61b4bbe0f4b79c873b39976 100755 (executable)
 #!/usr/bin/env bash
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
-# The official unmodified version of the script can be found at
-# https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
+set -eux
 
-set -e
+COVERITY_SCAN_TOOL_BASE="/tmp/coverity-scan-analysis"
+COVERITY_SCAN_PROJECT_NAME="systemd/systemd"
 
-# Declare build command
-COVERITY_SCAN_BUILD_COMMAND="ninja -C cov-build"
+function coverity_install_script {
+    local platform tool_url tool_archive
 
-# Environment check
-# Use default values if not set
-SCAN_URL=${SCAN_URL:="https://scan.coverity.com"}
-TOOL_BASE=${TOOL_BASE:="/tmp/coverity-scan-analysis"}
-UPLOAD_URL=${UPLOAD_URL:="https://scan.coverity.com/builds"}
+    platform=$(uname)
+    tool_url="https://scan.coverity.com/download/${platform}"
+    tool_archive="/tmp/cov-analysis-${platform}.tgz"
 
-# These must be set by environment
-echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
-[ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
-[ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
-[ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
-[ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
-[ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1
+    set +x # this is supposed to hide COVERITY_SCAN_TOKEN
+    echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
+    wget -nv -O "$tool_archive" "$tool_url" --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=${COVERITY_SCAN_TOKEN:?}"
+    set -x
 
-# Verify this branch should run
-if [[ "${CURRENT_REF^^}" =~ "${COVERITY_SCAN_BRANCH_PATTERN^^}" ]]; then
-    echo -e "\033[33;1mCoverity Scan configured to run on branch ${CURRENT_REF}\033[0m"
-else
-    echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${CURRENT_REF}\033[0m"
-    exit 1
-fi
-
-# Verify upload is permitted
-AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
-if [ "$AUTH_RES" = "Access denied" ]; then
-    echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
-    exit 1
-else
-    AUTH=`echo $AUTH_RES | jq .upload_permitted`
-    if [ "$AUTH" = "true" ]; then
-        echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
-    else
-        WHEN=`echo $AUTH_RES | jq .next_upload_permitted_at`
-        echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
-        exit 1
-    fi
-fi
-
-TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
-export PATH="$TOOL_DIR/bin:$PATH"
-
-# Disable CCACHE for cov-build to compilation units correctly
-export CCACHE_DISABLE=1
-
-# FUNCTION DEFINITIONS
-# --------------------
-_help()
-{
-    # displays help and exits
-    cat <<-EOF
-               USAGE: $0 [CMD] [OPTIONS]
-
-               CMD
-                 build   Issue Coverity build
-                 upload  Upload coverity archive for analysis
-              Note: By default, archive is created from default results directory.
-                    To provide custom archive or results directory, see --result-dir
-                    and --tar options below.
-
-               OPTIONS
-                 -h,--help     Display this menu and exits
-
-                 Applicable to build command
-                 ---------------------------
-                 -o,--out-dir  Specify Coverity intermediate directory (defaults to 'cov-int')
-                 -t,--tar      bool, archive the output to .tgz file (defaults to false)
-
-                 Applicable to upload command
-                 ----------------------------
-                 -d, --result-dir   Specify result directory if different from default ('cov-int')
-                 -t, --tar ARCHIVE  Use custom .tgz archive instead of intermediate directory or pre-archived .tgz
-                         (by default 'analysis-result.tgz'
-       EOF
-    return;
-}
-
-_pack()
-{
-    RESULTS_ARCHIVE=${RESULTS_ARCHIVE:-'analysis-results.tgz'}
-
-    echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
-    tar czf $RESULTS_ARCHIVE $RESULTS_DIR
-    SHA=`git rev-parse --short HEAD`
-
-    PACKED=true
+    mkdir -p "$COVERITY_SCAN_TOOL_BASE"
+    pushd "$COVERITY_SCAN_TOOL_BASE"
+    tar xzf "$tool_archive"
+    popd
 }
 
+function run_coverity {
+    local results_dir tool_dir results_archive sha response status_code
 
-_build()
-{
-    echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
-    local _cov_build_options=""
-    #local _cov_build_options="--return-emit-failures 8 --parse-error-threshold 85"
-    eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
-    COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $_cov_build_options sh -c "$COVERITY_SCAN_BUILD_COMMAND"
-    cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt
+    results_dir="cov-int"
+    tool_dir=$(find "$COVERITY_SCAN_TOOL_BASE" -type d -name 'cov-analysis*')
+    results_archive="analysis-results.tgz"
+    sha=$(git rev-parse --short HEAD)
 
-    if [ $? != 0 ]; then
-       echo -e "\033[33;1mCoverity Scan Build failed: $TEXT.\033[0m"
-       return 1
-    fi
-
-    [ -z $TAR ] || [ $TAR = false ] && return 0
+    meson -Dman=false build
+    COVERITY_UNSUPPORTED=1 "$tool_dir/bin/cov-build" --dir "$results_dir" sh -c "ninja -C ./build -v"
+    "$tool_dir/bin/cov-import-scm" --dir "$results_dir" --scm git --log "$results_dir/scm_log.txt"
 
-    if [ "$TAR" = true ]; then
-       _pack
-    fi
-}
+    tar czf "$results_archive" "$results_dir"
 
-
-_upload()
-{
-    # pack results
-    [ -z $PACKED ] || [ $PACKED = false ] && _pack
-
-    # Upload results
+    set +x # this is supposed to hide COVERITY_SCAN_TOKEN
     echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
     response=$(curl \
-                  --silent --write-out "\n%{http_code}\n" \
-                  --form project=$COVERITY_SCAN_PROJECT_NAME \
-                  --form token=$COVERITY_SCAN_TOKEN \
-                  --form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
-                  --form file=@$RESULTS_ARCHIVE \
-                  --form version=$SHA \
-                  --form description="Travis CI build" \
-                  $UPLOAD_URL)
+               --silent --write-out "\n%{http_code}\n" \
+               --form project="$COVERITY_SCAN_PROJECT_NAME" \
+               --form token="${COVERITY_SCAN_TOKEN:?}" \
+               --form email="${COVERITY_SCAN_NOTIFICATION_EMAIL:?}" \
+               --form file="@$results_archive" \
+               --form version="$sha" \
+               --form description="Daily build" \
+               https://scan.coverity.com/builds)
     printf "\033[33;1mThe response is\033[0m\n%s\n" "$response"
     status_code=$(echo "$response" | sed -n '$p')
-    # Coverity Scan used to respond with 201 on successfully receiving analysis results.
-    # Now for some reason it sends 200 and may change back in the foreseeable future.
-    # See https://github.com/pmem/pmdk/commit/7b103fd2dd54b2e5974f71fb65c81ab3713c12c5
     if [ "$status_code" != "200" ]; then
-       TEXT=$(echo "$response" | sed '$d')
-       echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
-       exit 1
+        echo -e "\033[33;1mCoverity Scan upload failed: $(echo "$response" | sed '$d').\033[0m"
+        return 1
     fi
-
-    echo -e "\n\033[33;1mCoverity Scan Analysis completed successfully.\033[0m"
-    exit 0
+    set -x
 }
 
-# PARSE COMMAND LINE OPTIONS
-# --------------------------
-
-case $1 in
-    -h|--help)
-       _help
-       exit 0
-       ;;
-    build)
-       CMD='build'
-       TEMP=`getopt -o ho:t --long help,out-dir:,tar -n '$0' -- "$@"`
-       _ec=$?
-       [[ $_ec -gt 0 ]] && _help && exit $_ec
-       shift
-       ;;
-    upload)
-       CMD='upload'
-       TEMP=`getopt -o hd:t: --long help,result-dir:tar: -n '$0' -- "$@"`
-       _ec=$?
-       [[ $_ec -gt 0 ]] && _help && exit $_ec
-       shift
-       ;;
-    *)
-       _help && exit 1 ;;
-esac
-
-RESULTS_DIR='cov-int'
-
-eval set -- "$TEMP"
-if [ $? != 0 ] ; then exit 1 ; fi
-
-# extract options and their arguments into variables.
-if [[ $CMD == 'build' ]]; then
-    TAR=false
-    while true ; do
-       case $1 in
-           -h|--help)
-               _help
-               exit 0
-               ;;
-           -o|--out-dir)
-               RESULTS_DIR="$2"
-               shift 2
-               ;;
-           -t|--tar)
-               TAR=true
-               shift
-               ;;
-           --) _build; shift ; break ;;
-           *) echo "Internal error" ; _help && exit 6 ;;
-       esac
-    done
-
-elif [[ $CMD == 'upload' ]]; then
-    while true ; do
-       case $1 in
-           -h|--help)
-               _help
-               exit 0
-               ;;
-           -d|--result-dir)
-               CHANGE_DEFAULT_DIR=true
-               RESULTS_DIR="$2"
-               shift 2
-               ;;
-           -t|--tar)
-               RESULTS_ARCHIVE="$2"
-               [ -z $CHANGE_DEFAULT_DIR ] || [ $CHANGE_DEFAULT_DIR = false ] && PACKED=true
-               shift 2
-               ;;
-           --) _upload; shift ; break ;;
-           *) echo "Internal error" ; _help && exit 6 ;;
-       esac
-    done
-
-fi
+coverity_install_script
+run_coverity
diff --git a/tools/get-coverity.sh b/tools/get-coverity.sh
deleted file mode 100755 (executable)
index b067ed2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-# Download and extract coverity tool
-
-set -e
-set -o pipefail
-
-# Environment check
-if [ -z "$COVERITY_SCAN_TOKEN" ]; then
-    echo >&2 'ERROR: COVERITY_SCAN_TOKEN must be set'
-    exit 1
-fi
-
-# Use default values if not set
-PLATFORM="$(uname)"
-TOOL_BASE="${TOOL_BASE:-/tmp/coverity-scan-analysis}"
-TOOL_ARCHIVE="${TOOL_ARCHIVE:-/tmp/cov-analysis-${PLATFORM}.tgz}"
-TOOL_URL="https://scan.coverity.com/download/${PLATFORM}"
-
-# Make sure wget is installed
-sudo apt-get update && sudo apt-get -y install wget
-
-# Get coverity tool
-if [ ! -d "$TOOL_BASE" ]; then
-    # Download Coverity Scan Analysis Tool
-    if [ ! -e "$TOOL_ARCHIVE" ]; then
-        echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
-        wget -nv -O "$TOOL_ARCHIVE" "$TOOL_URL" --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=$COVERITY_SCAN_TOKEN"
-    fi
-
-    # Extract Coverity Scan Analysis Tool
-    echo -e "\033[33;1mExtracting Coverity Scan Analysis Tool...\033[0m"
-    mkdir -p "$TOOL_BASE"
-    pushd "$TOOL_BASE"
-    tar xzf "$TOOL_ARCHIVE"
-    popd
-fi
-
-echo -e "\033[33;1mCoverity Scan Analysis Tool can be found at $TOOL_BASE ...\033[0m"
diff --git a/units/initrd-parse-etc.service b/units/initrd-parse-etc.service
deleted file mode 100644 (file)
index 38df728..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#  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.
-
-[Unit]
-Description=Reload Configuration from the Real Root
-DefaultDependencies=no
-Requires=initrd-root-fs.target
-After=initrd-root-fs.target
-OnFailure=emergency.target
-OnFailureJobMode=replace-irreversibly
-AssertPathExists=/etc/initrd-release
-
-[Service]
-Type=oneshot
-ExecStartPre=-systemctl daemon-reload
-# we have to retrigger initrd-fs.target after daemon-reload
-ExecStart=-systemctl --no-block start initrd-fs.target
-ExecStart=systemctl --no-block start initrd-cleanup.service
diff --git a/units/initrd-parse-etc.service.in b/units/initrd-parse-etc.service.in
new file mode 100644 (file)
index 0000000..fe0e860
--- /dev/null
@@ -0,0 +1,33 @@
+#  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.
+
+[Unit]
+Description=Mountpoints Configured in the Real Root
+AssertPathExists=/etc/initrd-release
+
+DefaultDependencies=no
+Requires=initrd-root-fs.target
+After=initrd-root-fs.target
+
+OnFailure=emergency.target
+OnFailureJobMode=replace-irreversibly
+
+[Service]
+Type=oneshot
+
+# FIXME: once dracut is patched to install the symlink, change to:
+# ExecStart={{ROOTLIBEXECDIR}}/systemd-sysroot-fstab-check
+ExecStart=@{{SYSTEM_GENERATOR_DIR}}/systemd-fstab-generator systemd-sysroot-fstab-check
+
+# We want to enqueue initrd-cleanup.service/start after we finished the part
+# above. It can't be part of the initial transaction, because non-oneshot units
+# use Conflicts=initrd-cleanup.service to be terminated before we switch root.
+# Effectively, initrd-parse-etc.service acts as a synchronization point after
+# which cleanup of the initrd processes starts.
+ExecStart=systemctl --no-block start initrd-cleanup.service
index 40f784ec683a155664fa1d8591d6b4029150103d..2010a5566f030aad7e8de95982aca24deef1793f 100644 (file)
@@ -36,7 +36,6 @@ units = [
         ['suspend-then-hibernate.target',       'ENABLE_HIBERNATE'],
         ['initrd-cleanup.service',              'ENABLE_INITRD'],
         ['initrd-fs.target',                    'ENABLE_INITRD'],
-        ['initrd-parse-etc.service',            'ENABLE_INITRD'],
         ['initrd-root-device.target',           'ENABLE_INITRD'],
         ['initrd-root-fs.target',               'ENABLE_INITRD'],
         ['initrd-switch-root.service',          'ENABLE_INITRD'],
@@ -179,6 +178,7 @@ in_units = [
         ['emergency.service',                    ''],
         ['getty@.service',                       '',
          'autovt@.service'],
+        ['initrd-parse-etc.service',             'ENABLE_INITRD'],
         ['kmod-static-nodes.service',            'HAVE_KMOD ENABLE_TMPFILES',
          'sysinit.target.wants/'],
         ['quotaon.service',                      'ENABLE_QUOTACHECK'],
index 95dd2665b28132713635e713897e8eb8ae62ba36..d15129e7f0ace9d4f15b791846fd1c150a9dcb6f 100644 (file)
@@ -25,6 +25,7 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_N
 DeviceAllow=char-* rw
 ExecStart=!!{{ROOTLIBEXECDIR}}/systemd-networkd
 ExecReload=networkctl reload
+FileDescriptorStoreMax=512
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
 NoNewPrivileges=yes