From ecfb185f0d39a60ba54218cf7764ee8697131d59 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sun, 11 Jun 2023 23:01:56 +0100 Subject: [PATCH] New upstream version 252.11 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/build_test.sh | 2 +- .github/workflows/linter.yml | 2 +- .github/workflows/make_release.yml | 24 ++ .github/workflows/mkosi.yml | 6 - NEWS | 2 +- README | 2 +- TODO | 2 +- docs/NETWORK_ONLINE.md | 2 +- docs/UIDS-GIDS.md | 2 +- docs/USER_RECORD.md | 2 +- hwdb.d/60-evdev.hwdb | 7 + hwdb.d/60-keyboard.hwdb | 40 +- hwdb.d/60-sensor.hwdb | 35 ++ hwdb.d/70-joystick.hwdb | 5 - hwdb.d/70-mouse.hwdb | 17 + hwdb.d/70-touchpad.hwdb | 5 - man/custom-entities.ent.in | 4 +- man/file-hierarchy.xml | 2 +- man/html.in | 6 +- man/logcontrol-example.c | 232 ++++++++++++ man/networkctl.xml | 4 +- man/org.freedesktop.LogControl1.xml | 14 + man/org.freedesktop.systemd1.xml | 11 +- man/print-unit-path-call-method.c | 51 +++ man/print-unit-path.c | 41 +-- man/resolved.conf.xml | 24 +- man/rules/meson.build | 3 +- man/sd_bus_call_method.xml | 13 + man/sd_bus_default.xml | 15 +- man/systemctl.xml | 2 +- man/systemd-analyze.xml | 2 +- man/systemd-bless-boot.service.xml | 4 +- man/systemd-coredump.xml | 6 +- man/systemd-dissect.xml | 2 +- man/systemd-fsck@.service.xml | 26 +- man/systemd-journal-remote.service.xml | 2 + man/systemd-makefs@.service.xml | 7 +- man/systemd-measure.xml | 2 +- man/systemd-mount.xml | 2 +- man/systemd-network-generator.service.xml | 2 +- man/systemd-nspawn.xml | 2 +- man/systemd-random-seed.service.xml | 2 +- man/systemd-sleep.conf.xml | 55 +-- man/systemd-system.conf.xml | 10 +- man/systemd-tmpfiles.xml | 6 +- man/systemd-userdbd.service.xml | 2 +- man/systemd.exec.xml | 21 +- man/systemd.generator.xml | 10 +- man/systemd.netdev.xml | 4 +- man/systemd.resource-control.xml | 222 +++++++++--- man/systemd.service.xml | 3 +- man/systemd.unit.xml | 44 ++- man/tmpfiles.d.xml | 2 +- man/udev.xml | 15 +- meson.build | 3 + meson_options.txt | 2 +- rules.d/60-persistent-storage.rules | 8 + shell-completion/bash/busctl | 2 +- shell-completion/bash/coredumpctl | 8 +- shell-completion/bash/portablectl | 6 +- shell-completion/zsh/_busctl | 1 + shell-completion/zsh/_systemctl.in | 54 ++- shell-completion/zsh/_timedatectl | 2 + src/activate/activate.c | 14 +- src/analyze/analyze-syscall-filter.c | 37 +- src/ask-password/ask-password.c | 4 + src/basic/audit-util.c | 61 +++- src/basic/capability-util.c | 1 + src/basic/cgroup-util.c | 1 + src/basic/coverage.h | 32 +- src/basic/dirent-util.h | 2 + src/basic/hash-funcs.h | 2 +- src/basic/list.h | 7 +- src/basic/log.c | 19 + src/basic/log.h | 1 + src/basic/macro.h | 18 +- src/basic/memory-util.c | 1 + src/basic/missing_threads.h | 15 + src/basic/mountpoint-util.c | 10 +- src/basic/process-util.c | 2 + src/basic/random-util.c | 1 + src/basic/ratelimit.c | 18 + src/basic/ratelimit.h | 3 + src/basic/signal-util.c | 1 + src/basic/socket-util.c | 30 +- src/basic/socket-util.h | 2 +- src/basic/stat-util.c | 4 +- src/basic/string-util.h | 12 + src/basic/syscall-list.txt | 1 + src/basic/syscalls-alpha.txt | 1 + src/basic/syscalls-arc.txt | 1 + src/basic/syscalls-arm.txt | 1 + src/basic/syscalls-arm64.txt | 1 + src/basic/syscalls-i386.txt | 1 + src/basic/syscalls-ia64.txt | 1 + src/basic/syscalls-loongarch64.txt | 1 + src/basic/syscalls-m68k.txt | 1 + src/basic/syscalls-mips64.txt | 1 + src/basic/syscalls-mips64n32.txt | 1 + src/basic/syscalls-mipso32.txt | 1 + src/basic/syscalls-parisc.txt | 1 + src/basic/syscalls-powerpc.txt | 1 + src/basic/syscalls-powerpc64.txt | 1 + src/basic/syscalls-riscv32.txt | 1 + src/basic/syscalls-riscv64.txt | 1 + src/basic/syscalls-s390.txt | 3 +- src/basic/syscalls-s390x.txt | 3 +- src/basic/syscalls-sparc.txt | 1 + src/basic/syscalls-x86_64.txt | 1 + src/basic/time-util.c | 1 + src/basic/user-util.c | 1 - src/basic/virt.c | 7 +- src/boot/bootctl.c | 33 +- src/boot/efi/meson.build | 26 +- src/boot/efi/util.h | 2 +- src/boot/pcrphase.c | 2 +- src/busctl/busctl.c | 30 +- src/cgls/cgls.c | 3 + src/core/dbus-manager.c | 34 +- src/core/dbus-service.c | 25 +- src/core/dbus-unit.c | 27 +- src/core/dbus.c | 3 + src/core/dbus.h | 1 + src/core/device.c | 5 +- src/core/execute.c | 1 + src/core/job.c | 8 +- src/core/job.h | 2 +- src/core/kmod-setup.c | 10 +- src/core/load-fragment.c | 10 +- src/core/main.c | 56 +-- src/core/manager-serialize.c | 25 +- src/core/manager.c | 74 +++- src/core/manager.h | 3 + src/core/mount.c | 17 +- src/core/org.freedesktop.systemd1.policy.in | 10 + src/core/path.c | 72 +++- src/core/path.h | 2 + src/core/scope.c | 2 +- src/core/service.c | 11 +- src/core/slice.c | 7 +- src/core/system.conf.in | 2 +- src/core/timer.c | 10 +- src/core/transaction.c | 30 +- src/core/unit.c | 23 +- src/core/unit.h | 1 + src/coredump/coredump.c | 149 +++----- src/cryptenroll/cryptenroll-list.c | 11 +- src/cryptenroll/cryptenroll-password.c | 2 +- src/cryptenroll/cryptenroll.c | 10 +- src/fsck/fsck.c | 9 +- src/fstab-generator/fstab-generator.c | 2 +- src/gpt-auto-generator/gpt-auto-generator.c | 2 +- src/home/homed-home.c | 4 +- src/home/homed-manager.c | 2 +- src/home/homework-luks.c | 13 +- src/home/pam_systemd_home.c | 13 +- src/journal-remote/fuzz-journal-remote.c | 23 +- src/journal/cat.c | 3 + src/journal/journalctl.c | 16 +- src/journal/journald-server.c | 2 +- src/journal/test-journal-interleaving.c | 2 +- src/libsystemd-network/test-dhcp-client.c | 2 +- src/libsystemd/sd-bus/bus-creds.c | 4 +- src/libsystemd/sd-bus/bus-internal.h | 2 +- src/libsystemd/sd-bus/bus-message.c | 14 +- src/libsystemd/sd-bus/sd-bus.c | 5 +- src/libsystemd/sd-device/device-enumerator.c | 3 +- src/libsystemd/sd-device/test-sd-device.c | 2 +- src/libsystemd/sd-event/sd-event.c | 2 +- src/libsystemd/sd-event/test-event.c | 2 +- src/libsystemd/sd-id128/sd-id128.c | 1 + src/libsystemd/sd-journal/catalog.c | 6 +- src/libsystemd/sd-journal/journal-file.c | 31 +- src/libsystemd/sd-journal/journal-vacuum.c | 11 +- src/libsystemd/sd-journal/test-catalog.c | 2 +- src/libsystemd/sd-resolve/sd-resolve.c | 1 + src/libudev/test-libudev.c | 6 +- src/locale/localed-util.c | 10 +- src/login/inhibit.c | 3 + src/login/logind-inhibit.c | 1 + src/login/pam_systemd.c | 6 +- src/machine/machinectl.c | 10 +- src/machine/operation.c | 2 +- src/network/netdev/vlan.c | 19 +- src/network/networkd-link.c | 2 +- src/network/networkd-route-util.c | 1 + src/network/tc/tbf.c | 6 +- src/network/wait-online/manager.c | 10 +- src/nspawn/nspawn-mount.c | 4 +- src/nspawn/nspawn-oci.c | 13 +- src/nspawn/nspawn-settings.c | 2 + src/nspawn/nspawn.c | 5 + src/nss-systemd/nss-systemd.c | 1 + src/oom/oomd-manager.c | 5 +- src/oom/oomd-util.c | 4 +- src/oom/oomd.c | 4 +- src/partition/repart.c | 49 ++- src/portable/portabled-operation.c | 2 +- src/resolve/resolved-dns-packet.h | 4 +- src/resolve/resolved-dns-rr.c | 4 +- src/resolve/resolved-manager.c | 6 +- src/resolve/test-resolved-etc-hosts.c | 4 +- src/run/run.c | 3 + src/shared/bpf-program.c | 3 + src/shared/bus-get-properties.c | 4 +- src/shared/bus-unit-util.c | 2 +- src/shared/cgroup-setup.c | 1 + src/shared/coredump-util.c | 7 +- src/shared/coredump-util.h | 3 + src/shared/dissect-image.c | 28 +- src/shared/exec-util.c | 2 +- src/shared/fdset.c | 32 +- src/shared/fdset.h | 2 +- src/shared/find-esp.c | 2 +- src/shared/json.c | 8 +- src/shared/mkfs-util.c | 2 + src/shared/mount-util.c | 4 +- src/shared/pam-util.c | 23 +- src/shared/pam-util.h | 6 +- src/shared/psi-util.c | 1 + src/shared/rm-rf.c | 161 +++++++-- src/shared/seccomp-util.c | 19 +- src/shared/securebits-util.h | 2 + src/shared/udev-util.c | 19 +- src/shared/uid-alloc-range.c | 1 + src/shared/varlink.c | 4 +- src/shared/xml.c | 12 +- src/shutdown/shutdown.c | 4 + src/sleep/sleep.c | 5 +- src/sysext/sysext.c | 2 +- src/systemctl/systemctl-list-dependencies.c | 17 +- src/systemctl/systemctl-start-unit.c | 10 +- src/systemd/meson.build | 7 + src/sysupdate/sysupdate.c | 2 +- src/sysusers/sysusers.c | 36 +- src/test/test-bpf-devices.c | 20 +- src/test/test-compress-benchmark.c | 2 +- src/test/test-copy.c | 12 +- src/test/test-coredump-util.c | 2 + src/test/test-date.c | 4 +- src/test/test-ellipsize.c | 2 +- src/test/test-env-file.c | 20 +- src/test/test-env-util.c | 44 +++ src/test/test-escape.c | 14 +- src/test/test-execve.c | 2 +- src/test/test-fd-util.c | 1 + src/test/test-fdset.c | 44 ++- src/test/test-fileio.c | 4 +- src/test/test-json.c | 2 +- src/test/test-nss-hosts.c | 6 +- src/test/test-rm-rf.c | 64 +++- src/test/test-sleep.c | 2 +- src/test/test-specifier.c | 27 ++ src/test/test-strbuf.c | 4 +- src/test/test-string-util.c | 19 +- src/test/test-strv.c | 4 +- src/test/test-time-util.c | 2 +- src/test/test-udev-util.c | 5 + src/test/test-unit-name.c | 2 +- src/test/test-utf8.c | 6 +- src/timesync/timesyncd-manager.c | 4 +- src/tmpfiles/tmpfiles.c | 2 +- src/udev/udev-builtin-path_id.c | 10 +- src/udev/udev-rules.c | 8 +- src/udev/udevadm-lock.c | 3 + src/udev/udevadm.c | 3 + src/userdb/userdbctl.c | 7 +- .../test-xdg-autostart.c | 4 +- .../xdg-autostart-service.c | 3 +- test/README.testsuite | 10 +- test/TEST-26-SYSTEMCTL/test.sh | 4 + .../fuzz-nspawn-oci/invalid-read-magic-string | 1 + .../invalid-read-magic-string2 | 1 + test/test-fstab-generator.sh | 4 + test/test-functions | 40 +- .../conf/21-vlan.netdev.d/override.conf | 10 +- test/test-network/systemd-networkd-tests.py | 26 +- .../test63-issue-24577-dep.service | 4 + .../test63-issue-24577.path | 3 + .../test63-issue-24577.service | 8 + test/udev-test.pl | 10 +- test/units/testsuite-03.sh | 6 +- test/units/testsuite-04.sh | 16 +- test/units/testsuite-16.sh | 66 ++++ test/units/testsuite-17.06.sh | 8 +- test/units/testsuite-17.07.sh | 8 +- test/units/testsuite-17.08.sh | 12 +- test/units/testsuite-17.09.sh | 4 +- test/units/testsuite-18.sh | 2 +- test/units/testsuite-19.sh | 30 +- test/units/testsuite-20.sh | 57 ++- test/units/testsuite-21.sh | 9 + test/units/testsuite-22.03.sh | 28 +- test/units/testsuite-22.08.sh | 6 +- test/units/testsuite-23.sh | 48 +-- test/units/testsuite-25.sh | 16 +- test/units/testsuite-26.sh | 15 + test/units/testsuite-29.sh | 2 +- test/units/testsuite-33.sh | 342 +++++++++--------- test/units/testsuite-34.sh | 9 +- test/units/testsuite-35.sh | 4 +- test/units/testsuite-39.sh | 4 +- test/units/testsuite-41.sh | 22 +- test/units/testsuite-42.sh | 54 +-- test/units/testsuite-43.sh | 38 +- test/units/testsuite-44.sh | 2 +- test/units/testsuite-45.sh | 34 +- test/units/testsuite-46.sh | 146 +++++++- test/units/testsuite-50.sh | 4 +- test/units/testsuite-54.sh | 76 ++-- test/units/testsuite-56.sh | 10 +- test/units/testsuite-57-retry-fail.service | 9 + test/units/testsuite-57-retry-upheld.service | 10 + test/units/testsuite-57-retry-uphold.service | 7 + test/units/testsuite-57.sh | 27 ++ test/units/testsuite-60.sh | 4 +- test/units/testsuite-63.sh | 43 ++- test/units/testsuite-64.sh | 15 +- test/units/testsuite-65.sh | 58 +-- test/units/testsuite-70.sh | 83 ++++- test/units/testsuite-73.sh | 9 +- test/units/testsuite-74.cgls.sh | 3 +- test/units/testsuite-75.sh | 2 +- units/systemd-coredump.socket | 2 +- units/systemd-hostnamed.service.in | 2 +- .../systemd-networkd-wait-online@.service.in | 1 + units/systemd-networkd.service.in | 5 +- units/systemd-oomd.service.in | 1 + units/systemd-oomd.socket | 8 +- units/systemd-portabled.service.in | 1 + units/systemd-resolved.service.in | 4 +- units/systemd-sysext.service | 2 +- units/systemd-time-wait-sync.service.in | 2 +- units/user@.service.in | 2 +- 335 files changed, 3479 insertions(+), 1363 deletions(-) create mode 100644 .github/workflows/make_release.yml create mode 100644 man/logcontrol-example.c create mode 100644 man/print-unit-path-call-method.c create mode 100644 src/basic/missing_threads.h create mode 100644 test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string create mode 100644 test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string2 create mode 100644 test/testsuite-63.units/test63-issue-24577-dep.service create mode 100644 test/testsuite-63.units/test63-issue-24577.path create mode 100644 test/testsuite-63.units/test63-issue-24577.service create mode 100644 test/units/testsuite-57-retry-fail.service create mode 100644 test/units/testsuite-57-retry-upheld.service create mode 100644 test/units/testsuite-57-retry-uphold.service diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d25f5ea68..a0dc872ea 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -26,7 +26,7 @@ body: id: distro attributes: label: Used distribution - description: Used distribution and it's version + description: Used distribution and its version placeholder: Fedora 36 validations: required: false diff --git a/.github/workflows/build_test.sh b/.github/workflows/build_test.sh index b60db29ef..e08f470cf 100755 --- a/.github/workflows/build_test.sh +++ b/.github/workflows/build_test.sh @@ -11,7 +11,7 @@ ARGS=( "--optimization=0" "--optimization=s -Dgnu-efi=true -Defi-cflags=-m32 -Defi-libdir=/usr/lib32" "--optimization=3 -Db_lto=true -Ddns-over-tls=false" - "--optimization=3 -Db_lto=false" + "--optimization=3 -Db_lto=false -Dtpm2=false -Dlibfido2=false -Dp11kit=false" "--optimization=3 -Ddns-over-tls=openssl" "--optimization=3 -Dfexecve=true -Dstandalone-binaries=true -Dstatic-libsystemd=true -Dstatic-libudev=true" "-Db_ndebug=true" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 180cfbfdb..3a1fef6ee 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -29,7 +29,7 @@ jobs: fetch-depth: 0 - name: Lint Code Base - uses: github/super-linter/slim@01d3218744765b55c3b5ffbb27e50961e50c33c5 + uses: github/super-linter/slim@454ba4482ce2cd0c505bc592e83c06e1e37ade61 env: DEFAULT_BRANCH: main MULTI_STATUS: false diff --git a/.github/workflows/make_release.yml b/.github/workflows/make_release.yml new file mode 100644 index 000000000..9902a6c6a --- /dev/null +++ b/.github/workflows/make_release.yml @@ -0,0 +1,24 @@ +name: Make a Github release + +on: + push: + tags: + - "v*" + +permissions: + contents: read + +jobs: + release: + if: github.repository == 'systemd/systemd' || github.repository == 'systemd/systemd-stable' + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Release + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + prerelease: ${{ contains(github.ref_name, '-rc') }} + draft: ${{ github.repository == 'systemd/systemd' }} diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml index 523415517..af0b8fe06 100644 --- a/.github/workflows/mkosi.yml +++ b/.github/workflows/mkosi.yml @@ -39,16 +39,10 @@ jobs: release: testing - distro: ubuntu release: jammy - - distro: fedora - release: "37" - - distro: fedora - release: rawhide - distro: opensuse release: tumbleweed - distro: centos_epel release: 9-stream - - distro: centos_epel - release: 8-stream steps: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b diff --git a/NEWS b/NEWS index 86a993867..01166f95b 100644 --- a/NEWS +++ b/NEWS @@ -22,7 +22,7 @@ CHANGES WITH 252 ๐ŸŽƒ: * ConditionKernelVersion= checks that use the '=' or '!=' operators will now do simple string comparisons (instead of version comparisons - รก la stverscmp()). Version comparisons are still done for the + ร  la stverscmp()). Version comparisons are still done for the ordering operators '<', '>', '<=', '>='. Moreover, if no operator is specified, a shell-style glob match is now done. This creates a minor incompatibility compared to older systemd versions when the '*', '?', diff --git a/README b/README index b9d0137f9..8e7e8b5c8 100644 --- a/README +++ b/README @@ -299,7 +299,7 @@ USERS AND GROUPS: group to exist. New journal files will be readable by this group (but not writable), which may be used to grant specific users read access. In addition, system groups "wheel" and "adm" will be given read-only access - to journal files using systemd-tmpfiles.service. + to journal files using systemd-tmpfiles-setup.service. The journal remote daemon requires the "systemd-journal-remote" system user and group to exist. During execution this network facing service diff --git a/TODO b/TODO index 560ec4bca..93963c2c8 100644 --- a/TODO +++ b/TODO @@ -573,7 +573,7 @@ Features: what to do if support ended * pam_systemd: on interactive logins, maybe show SUPPORT_END information at - login time, รก la motd + login time, ร  la motd * sd-boot: instead of unconditionally deriving the ESP to search boot loader spec entries in from the paths of sd-boot binary, let's optionally allow it diff --git a/docs/NETWORK_ONLINE.md b/docs/NETWORK_ONLINE.md index 084f0d138..5e01ab6ef 100644 --- a/docs/NETWORK_ONLINE.md +++ b/docs/NETWORK_ONLINE.md @@ -152,7 +152,7 @@ For details, see the next question. ## What does "up" actually mean? -The services that are ordered before `network-online.target` define it's +The services that are ordered before `network-online.target` define its meaning. *Usually* means that all configured network devices are up and have an IP address assigned, but details may vary. In particular, configuration may affect which interfaces are taken into account. diff --git a/docs/UIDS-GIDS.md b/docs/UIDS-GIDS.md index 57e8f4d4f..db4cac4cc 100644 --- a/docs/UIDS-GIDS.md +++ b/docs/UIDS-GIDS.md @@ -301,7 +301,7 @@ means they should not be provided by any networked service (as those usually become available during late boot only), except if a local cache is kept that makes them available during early boot too (i.e. before networking is up). Specifically, system users need to be resolvable at least before -`systemd-udevd.service` and `systemd-tmpfiles.service` are started, as both +`systemd-udevd.service` and `systemd-tmpfiles-setup.service` are started, as both need to resolve system users โ€” but note that there might be more services requiring full resolvability of system users than just these two. diff --git a/docs/USER_RECORD.md b/docs/USER_RECORD.md index f330e8b13..9537d1d1d 100644 --- a/docs/USER_RECORD.md +++ b/docs/USER_RECORD.md @@ -635,7 +635,7 @@ field of `struct passwd`). `sshAuthorizedKeys` โ†’ An array of strings, each listing an SSH public key that is authorized to access the account. The strings should follow the same format -as the lines in the traditional `~/.ssh/authorized_key` file. +as the lines in the traditional `~/.ssh/authorized_keys` file. `pkcs11EncryptedKey` โ†’ An array of objects. Each element of the array should be an object consisting of three string fields: `uri` shall contain a PKCS#11 diff --git a/hwdb.d/60-evdev.hwdb b/hwdb.d/60-evdev.hwdb index 7a969a84b..56cb3d363 100644 --- a/hwdb.d/60-evdev.hwdb +++ b/hwdb.d/60-evdev.hwdb @@ -583,6 +583,13 @@ evdev:input:b0003v17EFp60B5* EVDEV_ABS_35=::12 EVDEV_ABS_36=::11 +# Lenovo Thinkpad L14 Gen1 (AMD) +evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadL14Gen1** + EVDEV_ABS_00=::44 + EVDEV_ABS_01=::50 + EVDEV_ABS_35=::44 + EVDEV_ABS_36=::50 + # Lenovo T460 evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T460:* EVDEV_ABS_00=1266:5677:44 diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb index 10dde4dbe..27113276c 100644 --- a/hwdb.d/60-keyboard.hwdb +++ b/hwdb.d/60-keyboard.hwdb @@ -398,7 +398,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:* KEYBOARD_KEY_88=! # wireless switch KEYBOARD_KEY_9e=!f21 -# Dell Latitude E7* +# Dell Latitude E[67]* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E6*:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E7*:* KEYBOARD_KEY_88=unknown # Fn-PrtScr rfkill - handled in HW @@ -549,6 +550,14 @@ evdev:input:b0003v18D1p8001* evdev:input:b0003v18D1p8007* KEYBOARD_KEY_b002f=reserved # Disable micmute key +########################################################### +# Haier +########################################################### + +# 7G-Series +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHaierComputer:pn7G-Series:* + KEYBOARD_KEY_91=wlan + ########################################################### # Hewlett Packard ########################################################### @@ -624,7 +633,7 @@ evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:* KEYBOARD_KEY_97=brightnessup # HP Laptop 15s-eq0023nl -evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPLaptop15s-eq0*:sku9MG38EA#ABZ:* +evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPLaptop15s-eq0*:sku9MG38EA*ABZ:* KEYBOARD_KEY_9d=102nd # Greater than/Less than # Elitebook @@ -925,7 +934,7 @@ evdev:input:b0003v17EFp6009* KEYBOARD_KEY_090010=f20 # Microphone mute button; should be micmute # Lenovo 3000 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr* KEYBOARD_KEY_8b=switchvideomode # Fn+F7 video KEYBOARD_KEY_96=wlan # Fn+F5 wireless KEYBOARD_KEY_97=sleep # Fn+F4 suspend @@ -937,7 +946,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn0769AP2:pvr3000N200:* KEYBOARD_KEY_b4=prog1 # Lenovo IdeaPad -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:* KEYBOARD_KEY_81=rfkill # does nothing in BIOS KEYBOARD_KEY_83=display_off # BIOS toggles screen state @@ -952,7 +961,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrIdeaPad5*:* KEYBOARD_KEY_81=insert # Thinkpad X200_Tablet -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*T*:rvn* KEYBOARD_KEY_5d=menu KEYBOARD_KEY_63=fn KEYBOARD_KEY_66=screenlock @@ -961,7 +970,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*:* KEYBOARD_KEY_6c=direction # rotate screen # ThinkPad X6 Tablet -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*:rvn* KEYBOARD_KEY_6c=direction # rotate KEYBOARD_KEY_68=leftmeta # toolbox KEYBOARD_KEY_6b=esc # escape @@ -985,20 +994,20 @@ evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:* KEYBOARD_KEY_42=f23 KEYBOARD_KEY_43=f22 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr* KEYBOARD_KEY_95=media KEYBOARD_KEY_a3=play -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr* KEYBOARD_KEY_f1=f21 KEYBOARD_KEY_ce=f20 # micmute -evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:* +evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr* KEYBOARD_KEY_a0=!mute KEYBOARD_KEY_ae=!volumedown KEYBOARD_KEY_b0=!volumeup -evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPadFlex5*:* +evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO:*:pvrIdeaPadFlex514IIL05:* KEYBOARD_KEY_a0=!mute KEYBOARD_KEY_ae=!volumedown KEYBOARD_KEY_b0=!volumeup @@ -1017,11 +1026,11 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO:pn81Q7*:pvrLenovoYogaS940:* KEYBOARD_KEY_b0=!volumeup # Lenovo Y50-70 -evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:* +evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:pvr* KEYBOARD_KEY_f3=f21 # Fn+F6 (toggle touchpad) # V480 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr* KEYBOARD_KEY_f1=f21 # Lenovo ThinkCentre M800z/M820z/M920z AIO machines @@ -1398,6 +1407,7 @@ evdev:input:b0003v1532p0200* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:* + KEYBOARD_KEY_76=f21 # Toggle touchpad, sends meta+ctrl+toggle KEYBOARD_KEY_91=config # MSIControl Center KEYBOARD_KEY_a0=mute # Fn+F9 KEYBOARD_KEY_ae=volumedown # Fn+F7 @@ -1438,8 +1448,6 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:* # Keymaps MSI Prestige And MSI Modern FnKeys and Special keys evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Prestige*:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Modern*:* - KEYBOARD_KEY_f1=f20 # Fn+F5 Micmute - KEYBOARD_KEY_76=f21 # Fn+F4 Toggle touchpad, sends meta+ctrl+toggle KEYBOARD_KEY_91=prog1 # Fn+F7 Creation Center, sometime F7 KEYBOARD_KEY_f2=prog2 # Fn+F12 Screen rotation KEYBOARD_KEY_8d=prog3 # Fn+A Change True Color selections @@ -2041,10 +2049,14 @@ evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:bd*:svnPositivoBahia-VAIO: ########################################################### # Positivo MASTER-N1110 evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnNP11G-E* +# Positivo (CF40CM-V2) +evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnCF40CM-V2* # Positivo DUO (k116) evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnK116* KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad +# Positivo (CG15D) +evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCG15D* # Positivo Motion (N14DP6, N14DP7, N14DP7-V2, N14DP9, N14JP6, N14KP6) evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnN14[DJK]P* KEYBOARD_KEY_76=f21 # Fn+f2 toggle touchpad diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb index 044fecdb3..f971f701c 100644 --- a/hwdb.d/60-sensor.hwdb +++ b/hwdb.d/60-sensor.hwdb @@ -171,6 +171,9 @@ sensor:modalias:acpi:SMO8500*:dmi:*svn*ASUSTeK*:*pn*TP300LAB:* sensor:modalias:acpi:BOSC0200*:dmi:*svn*ASUSTeK*:*pn*TP412UA:* ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1 +sensor:modalias:acpi:BOSC0200*:dmi:*svn*ASUSTeK*:pn*BR1100FKA:* + ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, -1 + ######################################### # Axxo ######################################### @@ -189,6 +192,15 @@ sensor:modalias:acpi:BMI0160*:dmi:*:svnAYANEO:pnAIR*:* sensor:modalias:acpi:BMI0160*:dmi:*:svnAYANEO:pn*NEXT*:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 +######################################### +# BMAX +######################################### + +# BMAX Y13 +sensor:modalias:acpi:KIOX010A:*:dmi:*:svnAMI:*:skuH2M6:* + ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1 + ACCEL_LOCATION=display + ######################################### # Chuwi ######################################### @@ -627,6 +639,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN4?WW:*:svnLENOVO:pn80SG:* sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN2?WW:*:svnLENOVO:pn80SG:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 +# IdeaPad Miix 310 BIOS version bvr1HCN3?WW (variant 3) +sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN3?WW:*:svnLENOVO:pn80SG:* + ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 + # IdeaPad Miix 320, different batches use a different sensor sensor:modalias:acpi:*BOSC0200*:dmi:*:svnLENOVO*:pn80XF:* sensor:modalias:acpi:SMO8840*:dmi:*:svnLENOVO:pn80XF:pvrLenovoMIIX320:* @@ -648,6 +664,10 @@ sensor:modalias:i2c:bmc150_accel:dmi:*:svnLENOVO:*:pvrLenovoYoga300-11IBR:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, 1, 0; 0, 0, -1 ACCEL_LOCATION=base +# Yoga Tablet 2 851F/L +sensor:modalias:acpi:ACCL0001*:dmi:*:svnLENOVO:pn60072:pvr851*:* + ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1 + # IdeaPad Duet 3 10IGL5 (82AT) sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82AT:* ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1 @@ -704,12 +724,15 @@ sensor:modalias:acpi:KIOX000A*:dmi:*svnMEDION:pnE2215TMD60198:* sensor:modalias:acpi:KIOX010A*:dmi:*:svnMEDION:pnE*:* # Medion Akoya E3222 MD62450 sensor:modalias:acpi:KIOX010A*:dmi:*:svnMEDION:pnMEDION*:* +# and rebrands of the above +sensor:modalias:acpi:KIOX010A*:dmi:*:rvnMEDION:rnMEDION*:* ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 ACCEL_LOCATION=display # Same as above, but for base sensor sensor:modalias:acpi:KIOX020A*:dmi:*:svnMEDION:pnE*:* sensor:modalias:acpi:KIOX020A*:dmi:*:svnMEDION:pnMEDION*:* +sensor:modalias:acpi:KIOX020A*:dmi:*:rvnMEDION:rnMEDION*:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1 ACCEL_LOCATION=base @@ -805,6 +828,14 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/201 sensor:modalias:acpi:BMI0160*:dmi:*:rnONEXPLAYER:rvrV01:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1 +######################################### +# Passion +######################################### + +# Passion P612F +sensor:modalias:acpi:MXC6655*:dmi:*:svnDefaultstring*:pnP612F:* + ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 + ######################################### # Peaq ######################################### @@ -960,6 +991,10 @@ sensor:modalias:acpi:INVN6500*:dmi:*:svnTOSHIBA:pnTOSHIBAENCORE2WT8-B:* sensor:modalias:acpi:INVN6500*:dmi:*:svnTOSHIBA:pnTOSHIBAWT10-A-103:* ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 +# Toshiba Encore WT10A-102 tablet +sensor:modalias:acpi:INVN6500*:dmi:*:svnTOSHIBA:pnTOSHIBAWT10-A-102:* + ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 + ######################################### # Trekstor ######################################### diff --git a/hwdb.d/70-joystick.hwdb b/hwdb.d/70-joystick.hwdb index 9d5c4fc06..8e942c8c1 100644 --- a/hwdb.d/70-joystick.hwdb +++ b/hwdb.d/70-joystick.hwdb @@ -5,11 +5,6 @@ # The lookup keys are composed in: # 70-joystick.rules # -# Note: The format of the "joystick:" prefix match key is a -# contract between the rules file and the hardware data, it might -# change in later revisions to support more or better matches, it -# is not necessarily expected to be a stable ABI. -# # Match string format: # joystick::vp:name:: # diff --git a/hwdb.d/70-mouse.hwdb b/hwdb.d/70-mouse.hwdb index 4084019bd..159bc7862 100644 --- a/hwdb.d/70-mouse.hwdb +++ b/hwdb.d/70-mouse.hwdb @@ -153,6 +153,15 @@ mouse:*:name:*TrackBall*:* mouse:bluetooth:v05acp030d:name:*:* MOUSE_DPI=1300@1000 +########################################## +# Cherry +########################################## + +# Cherry MW 2310 +mouse:usb:v1A81p1701:name:G-Tech Wireless Dongle Mouse:* + KEYBOARD_KEY_90005=back + KEYBOARD_KEY_90004=forward + ########################################## # Chicony ########################################## @@ -388,6 +397,14 @@ mouse:usb:v046dpc08b:name:Logitech G502 HERO SE:* mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse:* MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000 +# Logitech G502 X (Wired) +mouse:usb:v046dpc098:name:Logitech, Inc. G502 X LIGHTSPEED:* +# Logitech G502 X (Wireless) +# The USB receiver is also used by other mice. See #27118. +# If you want to enable the entry, please copy below to your custom hwdb file. +#mouse:usb:v046dpc547:name:Logitech USB Receiver:* + MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000 + # Logitech G700 Laser Mouse (Wired) mouse:usb:v046dpc06b:name:Logitech G700 Laser Mouse:* # Logitech G700 Laser Mouse (Wireless) diff --git a/hwdb.d/70-touchpad.hwdb b/hwdb.d/70-touchpad.hwdb index 8194d9835..262bca3a1 100644 --- a/hwdb.d/70-touchpad.hwdb +++ b/hwdb.d/70-touchpad.hwdb @@ -5,11 +5,6 @@ # The lookup keys are composed in: # 70-touchpad.rules # -# Note: The format of the "touchpad:" prefix match key is a -# contract between the rules file and the hardware data, it might -# change in later revisions to support more or better matches, it -# is not necessarily expected to be a stable ABI. -# # Match string format: # touchpad::vp:name:: # diff --git a/man/custom-entities.ent.in b/man/custom-entities.ent.in index 6d662a380..d25340d5a 100644 --- a/man/custom-entities.ent.in +++ b/man/custom-entities.ent.in @@ -15,5 +15,5 @@ - - + + diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml index 4961f019f..9e91af906 100644 --- a/man/file-hierarchy.xml +++ b/man/file-hierarchy.xml @@ -737,7 +737,7 @@ /var/log/package/ - Persistent log data of the package. As above, the package should make sure to create this directory if necessary, possibly using tmpfiles.d5 or LogsDirectory= (see systemd.unit5), as it might be missing. + Persistent log data of the package. As above, the package should make sure to create this directory if necessary, possibly using tmpfiles.d5 or LogsDirectory= (see systemd.exec5), as it might be missing. /var/spool/package/ diff --git a/man/html.in b/man/html.in index 5e545b741..aaff9d138 100755 --- a/man/html.in +++ b/man/html.in @@ -14,7 +14,11 @@ target="man/$1.html" ninja -C "@BUILD_ROOT@" "$target" fullname="@BUILD_ROOT@/$target" -redirect="$(test -f "$fullname" && readlink "$fullname" || :)" +if [ -f "$fullname" ]; then + redirect="$(readlink "$fullname" || :)" +else + redirect="" +fi if [ -n "$redirect" ]; then ninja -C "@BUILD_ROOT@" "man/$redirect" diff --git a/man/logcontrol-example.c b/man/logcontrol-example.c new file mode 100644 index 000000000..734318da9 --- /dev/null +++ b/man/logcontrol-example.c @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: MIT-0 */ + +/* Implements the LogControl1 interface as per specification: + * https://www.freedesktop.org/software/systemd/man/org.freedesktop.LogControl1.html + * + * Compile with 'cc logcontrol-example.c $(pkg-config --libs --cflags libsystemd)' + * + * To get and set properties via busctl: + * + * $ busctl --user get-property org.freedesktop.Example \ + * /org/freedesktop/LogControl1 \ + * org.freedesktop.LogControl1 \ + * SyslogIdentifier + * s "example" + * $ busctl --user get-property org.freedesktop.Example \ + * /org/freedesktop/LogControl1 \ + * org.freedesktop.LogControl1 \ + * LogTarget + * s "journal" + * $ busctl --user get-property org.freedesktop.Example \ + * /org/freedesktop/LogControl1 \ + * org.freedesktop.LogControl1 \ + * LogLevel + * s "info" + * $ busctl --user set-property org.freedesktop.Example \ + * /org/freedesktop/LogControl1 \ + * org.freedesktop.LogControl1 \ + * LogLevel \ + * "s" debug + * $ busctl --user get-property org.freedesktop.Example \ + * /org/freedesktop/LogControl1 \ + * org.freedesktop.LogControl1 \ + * LogLevel + * s "debug" + */ + +#include +#include +#include +#include +#include +#include + +#define _cleanup_(f) __attribute__((cleanup(f))) + +#define check(log_level, x) ({ \ + int _r = (x); \ + errno = _r < 0 ? -_r : 0; \ + sd_journal_print((log_level), #x ": %m"); \ + if (_r < 0) \ + return EXIT_FAILURE; \ + }) + +typedef enum LogTarget { + LOG_TARGET_JOURNAL, + LOG_TARGET_KMSG, + LOG_TARGET_SYSLOG, + LOG_TARGET_CONSOLE, + _LOG_TARGET_MAX, +} LogTarget; + +static const char* const log_target_table[_LOG_TARGET_MAX] = { + [LOG_TARGET_JOURNAL] = "journal", + [LOG_TARGET_KMSG] = "kmsg", + [LOG_TARGET_SYSLOG] = "syslog", + [LOG_TARGET_CONSOLE] = "console", +}; + +static const char* const log_level_table[LOG_DEBUG + 1] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug", +}; + +typedef struct object { + const char *syslog_identifier; + LogTarget log_target; + int log_level; +} object; + +static int property_get( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + object *o = userdata; + + if (strcmp(property, "LogLevel") == 0) + return sd_bus_message_append(reply, "s", log_level_table[o->log_level]); + + if (strcmp(property, "LogTarget") == 0) + return sd_bus_message_append(reply, "s", log_target_table[o->log_target]); + + if (strcmp(property, "SyslogIdentifier") == 0) + return sd_bus_message_append(reply, "s", o->syslog_identifier); + + return sd_bus_error_setf(error, + SD_BUS_ERROR_UNKNOWN_PROPERTY, + "Unknown property '%s'", + property); +} + +static int property_set( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + object *o = userdata; + const char *value; + int r; + + r = sd_bus_message_read(message, "s", &value); + if (r < 0) + return r; + + if (strcmp(property, "LogLevel") == 0) { + for (int i = 0; i < LOG_DEBUG + 1; i++) + if (strcmp(value, log_level_table[i]) == 0) { + o->log_level = i; + return 0; + } + + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Invalid value for LogLevel: '%s'", + value); + } + + if (strcmp(property, "LogTarget") == 0) { + for (LogTarget i = 0; i < _LOG_TARGET_MAX; i++) + if (strcmp(value, log_target_table[i]) == 0) { + o->log_target = i; + return 0; + } + + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Invalid value for LogTarget: '%s'", + value); + } + + return sd_bus_error_setf(error, + SD_BUS_ERROR_UNKNOWN_PROPERTY, + "Unknown property '%s'", + property); +} + +/* https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html + */ +static const sd_bus_vtable vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_WRITABLE_PROPERTY( + "LogLevel", "s", + property_get, property_set, + 0, + 0), + SD_BUS_WRITABLE_PROPERTY( + "LogTarget", "s", + property_get, property_set, + 0, + 0), + SD_BUS_PROPERTY( + "SyslogIdentifier", "s", + property_get, + 0, + SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +}; + +int main(int argc, char **argv) { + /* The bus should be relinquished before the program terminates. The cleanup + * attribute allows us to do it nicely and cleanly whenever we exit the + * block. + */ + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + + object o = { + .log_level = LOG_INFO, + .log_target = LOG_TARGET_JOURNAL, + .syslog_identifier = "example", + }; + + /* Acquire a connection to the bus, letting the library work out the details. + * https://www.freedesktop.org/software/systemd/man/sd_bus_default.html + */ + check(o.log_level, sd_bus_default(&bus)); + + /* Publish an interface on the bus, specifying our well-known object access + * path and public interface name. + * https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html + * https://dbus.freedesktop.org/doc/dbus-tutorial.html + */ + check(o.log_level, sd_bus_add_object_vtable(bus, NULL, + "/org/freedesktop/LogControl1", + "org.freedesktop.LogControl1", + vtable, + &o)); + + /* By default the service is assigned an ephemeral name. Also add a fixed + * one, so that clients know whom to call. + * https://www.freedesktop.org/software/systemd/man/sd_bus_request_name.html + */ + check(o.log_level, sd_bus_request_name(bus, "org.freedesktop.Example", 0)); + + for (;;) { + /* https://www.freedesktop.org/software/systemd/man/sd_bus_wait.html + */ + check(o.log_level, sd_bus_wait(bus, UINT64_MAX)); + /* https://www.freedesktop.org/software/systemd/man/sd_bus_process.html + */ + check(o.log_level, sd_bus_process(bus, NULL)); + } + + /* https://www.freedesktop.org/software/systemd/man/sd_bus_release_name.html + */ + check(o.log_level, sd_bus_release_name(bus, "org.freedesktop.Example")); + + return 0; +} diff --git a/man/networkctl.xml b/man/networkctl.xml index f67ad99ad..94ec3dc63 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -18,7 +18,7 @@ networkctl - Query the status of network links + Query or modify the status of network links @@ -33,7 +33,7 @@ Description - networkctl may be used to introspect the + networkctl may be used to query or modify the state of the network links as seen by systemd-networkd. Please refer to systemd-networkd.service8 diff --git a/man/org.freedesktop.LogControl1.xml b/man/org.freedesktop.LogControl1.xml index da6dd7628..1694453ba 100644 --- a/man/org.freedesktop.LogControl1.xml +++ b/man/org.freedesktop.LogControl1.xml @@ -116,6 +116,20 @@ node /org/freedesktop/LogControl1 { for details about BusName=.) + + Example + + + Create a simple listener on the bus that implements LogControl1 + + + + This creates a simple server on the bus. It implements the LogControl1 interface by providing + the required properties and allowing to set the writable ones. It logs at the configured log level using + sd_journal_print3. + + + See Also diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 7dbf98def..a1f25dacf 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -1357,7 +1357,8 @@ node /org/freedesktop/systemd1 { DumpByFileDescriptor()/DumpUnitsMatchingPatternsByFileDescriptor() are usually the preferred interface, since it ensures the data can be passed reliably from the service manager to the client. Note though that they cannot work when communicating with the service manager - remotely, as file descriptors are strictly local to a system. + remotely, as file descriptors are strictly local to a system. All the Dump*() + methods are rate limited for unprivileged users. Reload() may be invoked to reload all unit files. @@ -1721,7 +1722,9 @@ node /org/freedesktop/systemd1 { UnsetAndSetEnvironment()) require org.freedesktop.systemd1.set-environment. Reload() and Reexecute() require - org.freedesktop.systemd1.reload-daemon. + org.freedesktop.systemd1.reload-daemon. Operations which dump internal + state require org.freedesktop.systemd1.bypass-dump-ratelimit to avoid + rate limits. @@ -2406,10 +2409,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { IgnoreOnIsolate, IgnoreOnSnapshot map directly to the corresponding configuration booleans in the unit file. - DefaultControlGroup contains the main control group of this unit as a - string. This refers to a group in systemd's own name=systemd hierarchy, which - systemd uses to watch and manipulate the unit and all its processes. - NeedDaemonReload is a boolean that indicates whether the configuration file this unit is loaded from (i.e. FragmentPath or SourcePath) has changed since the configuration was read and hence whether a configuration reload is recommended. diff --git a/man/print-unit-path-call-method.c b/man/print-unit-path-call-method.c new file mode 100644 index 000000000..f73dd073f --- /dev/null +++ b/man/print-unit-path-call-method.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: MIT-0 */ + +/* This is equivalent to: + * busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \ + * org.freedesktop.systemd1.Manager GetUnitByPID $$ + * + * Compile with 'cc print-unit-path-call-method.c -lsystemd' + */ + +#include +#include +#include +#include + +#include + +#define _cleanup_(f) __attribute__((cleanup(f))) +#define DESTINATION "org.freedesktop.systemd1" +#define PATH "/org/freedesktop/systemd1" +#define INTERFACE "org.freedesktop.systemd1.Manager" +#define MEMBER "GetUnitByPID" + +static int log_error(int error, const char *message) { + errno = -error; + fprintf(stderr, "%s: %m\n", message); + return error; +} + +int main(int argc, char **argv) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + r = sd_bus_open_system(&bus); + if (r < 0) + return log_error(r, "Failed to acquire bus"); + + r = sd_bus_call_method(bus, DESTINATION, PATH, INTERFACE, MEMBER, &error, &reply, "u", (unsigned) getpid()); + if (r < 0) + return log_error(r, MEMBER " call failed"); + + const char *ans; + r = sd_bus_message_read(reply, "o", &ans); + if (r < 0) + return log_error(r, "Failed to read reply"); + + printf("Unit path is \"%s\".\n", ans); + + return 0; +} diff --git a/man/print-unit-path.c b/man/print-unit-path.c index 44c827182..0b8931873 100644 --- a/man/print-unit-path.c +++ b/man/print-unit-path.c @@ -1,20 +1,20 @@ /* SPDX-License-Identifier: MIT-0 */ -#include -#include -#include -#include - -#include -#define _cleanup_(f) __attribute__((cleanup(f))) - /* This is equivalent to: * busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 \ * org.freedesktop.systemd1.Manager GetUnitByPID $$ * - * Compile with 'cc -lsystemd print-unit-path.c' + * Compile with 'cc print-unit-path.c -lsystemd' */ +#include +#include +#include +#include + +#include + +#define _cleanup_(f) __attribute__((cleanup(f))) #define DESTINATION "org.freedesktop.systemd1" #define PATH "/org/freedesktop/systemd1" #define INTERFACE "org.freedesktop.systemd1.Manager" @@ -26,12 +26,16 @@ static int log_error(int error, const char *message) { return error; } -static int print_unit_path(sd_bus *bus) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; +int main(int argc, char **argv) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; int r; + r = sd_bus_open_system(&bus); + if (r < 0) + return log_error(r, "Failed to acquire bus"); + r = sd_bus_message_new_method_call(bus, &m, DESTINATION, PATH, INTERFACE, MEMBER); if (r < 0) @@ -43,7 +47,7 @@ static int print_unit_path(sd_bus *bus) { r = sd_bus_call(bus, m, -1, &error, &reply); if (r < 0) - return log_error(r, "Call failed"); + return log_error(r, MEMBER " call failed"); const char *ans; r = sd_bus_message_read(reply, "o", &ans); @@ -54,14 +58,3 @@ static int print_unit_path(sd_bus *bus) { return 0; } - -int main(int argc, char **argv) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; - - r = sd_bus_open_system(&bus); - if (r < 0) - return log_error(r, "Failed to acquire bus"); - - print_unit_path(bus); -} diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 3c56b7674..2b9f48297 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -75,7 +75,7 @@ Domains= - A space-separated list of domains optionally prefixed with ~, + A space-separated list of domains, optionally prefixed with ~, used for two distinct purposes described below. Defaults to the empty list. Any domains not prefixed with ~ are used as search @@ -86,17 +86,23 @@ /etc/resolv.conf with the search keyword are used instead, if that file exists and any domains are configured in it. - The domains prefixed with ~ are called "routing domains". All domains listed - here (both search domains and routing domains after removing the ~ prefix) define - a search path that preferably directs DNS queries to this interface. This search path has an effect - only when suitable per-link DNS servers are known. Such servers may be defined through the - DNS= setting (see above) and dynamically at run time, for example from DHCP - leases. If no per-link DNS servers are known, routing domains have no effect. + The domains prefixed with ~ are called "route-only domains". All domains + listed here (both search domains and route-only domains after removing the + ~ prefix) define a search path that preferably directs DNS queries to this + interface. This search path has an effect only when suitable per-link DNS servers are known. Such + servers may be defined through the DNS= setting (see above) and dynamically at run + time, for example from DHCP leases. If no per-link DNS servers are known, route-only domains have no + effect. Use the construct ~. (which is composed from ~ to - indicate a routing domain and . to indicate the DNS root domain that is the + indicate a route-only domain and . to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the DNS servers defined for this link preferably for all - domains. + domains. + + See "Protocols and Routing" in + systemd-resolved.service8 + for details of how search and route-only domains are used. + diff --git a/man/rules/meson.build b/man/rules/meson.build index bb7799036..4819b15fa 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -890,7 +890,7 @@ manpages = [ ['systemd-firstboot', '1', ['systemd-firstboot.service'], 'ENABLE_FIRSTBOOT'], ['systemd-fsck@.service', '8', - ['systemd-fsck', 'systemd-fsck-root.service'], + ['systemd-fsck', 'systemd-fsck-root.service', 'systemd-fsck-usr.service'], ''], ['systemd-fstab-generator', '8', [], ''], ['systemd-getty-generator', '8', [], ''], @@ -952,6 +952,7 @@ manpages = [ ['systemd-makefs@.service', '8', ['systemd-growfs', + 'systemd-growfs-root.service', 'systemd-growfs@.service', 'systemd-makefs', 'systemd-mkswap@.service'], diff --git a/man/sd_bus_call_method.xml b/man/sd_bus_call_method.xml index 762ea11c0..7b525558d 100644 --- a/man/sd_bus_call_method.xml +++ b/man/sd_bus_call_method.xml @@ -126,6 +126,19 @@ + + Examples + + + Make a call to a D-Bus method that takes a single parameter + + + This defines a minimally useful program that will open a connection to the bus, call a method, + wait for the reply, and finally extract and print the answer. It does error handling and proper + memory management. + + + See Also diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml index f4b1d6a79..cee0748e1 100644 --- a/man/sd_bus_default.xml +++ b/man/sd_bus_default.xml @@ -110,13 +110,14 @@ Description sd_bus_default() acquires a bus - connection object to the user bus when invoked in user context, or - to the system bus otherwise. The connection object is associated - with the calling thread. Each time the function is invoked from - the same thread, the same object is returned, but its reference - count is increased by one, as long as at least one reference is - kept. When the last reference to the connection is dropped (using - the + connection object to the user bus when invoked from within a user + slice (any session under user-*.slice, e.g.: + user@1000.service), or to the system bus + otherwise. The connection object is associated with the calling + thread. Each time the function is invoked from the same thread, + the same object is returned, but its reference count is increased + by one, as long as at least one reference is kept. When the last + reference to the connection is dropped (using the sd_bus_unref3 call), the connection is terminated. Note that the connection is not automatically terminated when the associated thread ends. It diff --git a/man/systemctl.xml b/man/systemctl.xml index 997925892..a526640c8 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1136,7 +1136,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err - cancel JOBโ€ฆ + cancel JOBโ€ฆ Cancel one or more jobs specified on the command line diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index eeefff4b9..099f73f88 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -260,7 +260,7 @@ multi-user.target @47.820s Without any parameter, this command outputs a (usually very long) human-readable serialization of the complete service manager state. Optional glob pattern may be specified, causing the output to be limited to units whose names match one of the patterns. The output format is subject to change without - notice and should not be parsed by applications. + notice and should not be parsed by applications. This command is rate limited for unprivileged users. Show the internal state of user manager diff --git a/man/systemd-bless-boot.service.xml b/man/systemd-bless-boot.service.xml index 53a58b3a1..bccf22c5a 100644 --- a/man/systemd-bless-boot.service.xml +++ b/man/systemd-bless-boot.service.xml @@ -24,7 +24,7 @@ systemd-bless-boot.service - /usr/lib/systemd/system-bless-boot + /usr/lib/systemd/systemd-bless-boot @@ -50,7 +50,7 @@ Options - The /usr/lib/systemd/system-bless-boot executable may also be invoked from the + The /usr/lib/systemd/systemd-bless-boot executable may also be invoked from the command line, taking one of the following command arguments: diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml index cb9f47745..f7f6fcee7 100644 --- a/man/systemd-coredump.xml +++ b/man/systemd-coredump.xml @@ -60,6 +60,9 @@ files. Some metadata is attached to core files in the form of extended attributes, so the core files are useful for some purposes even without the full metadata available in the journal entry. + For further details see systemd Coredump + Handling. + Invocation of <command>systemd-coredump</command> @@ -430,7 +433,8 @@ user.coredump.exe="/usr/lib64/firefox/firefox" systemd-tmpfiles8, core5, sysctl.d5, - systemd-sysctl.service8. + systemd-sysctl.service8, + systemd Coredump Handling diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index 9528e91a4..b04dadc31 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -140,7 +140,7 @@ a directory where an OS image was mounted. All mounted partitions will be recursively unmounted, and the underlying loop device will be - removed, along with all it's partition sub-devices. + removed, along with all its partition sub-devices. diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml index a9aa0ffd0..403286829 100644 --- a/man/systemd-fsck@.service.xml +++ b/man/systemd-fsck@.service.xml @@ -18,6 +18,7 @@ systemd-fsck@.service systemd-fsck-root.service + systemd-fsck-usr.service systemd-fsck File system checker logic @@ -25,18 +26,20 @@ systemd-fsck@.service systemd-fsck-root.service + systemd-fsck-usr.service /usr/lib/systemd/systemd-fsck Description - systemd-fsck@.service and systemd-fsck-root.service are - services responsible for file system checks. They are instantiated for each device that is configured for - file system checking. systemd-fsck-root.service is responsible for file system - checks on the root file system, but only if the root filesystem was not checked in the initrd. - systemd-fsck@.service is used for all other file systems and for the root file - system in the initrd. + systemd-fsck@.service, systemd-fsck-root.service, and + systemd-fsck-usr.service are services responsible for file system checks. They are + instantiated for each device that is configured for file system checking. + systemd-fsck-root.service and systemd-fsck-usr.service are + responsible for file system checks on the root and /usr file system, respectively, but only if the root + filesystem was not checked in the initrd. systemd-fsck@.service is used for all + other file systems and for the root file system in the initrd. These services are started at boot if in /etc/fstab for the @@ -48,18 +51,17 @@ systemd-fsck does not know any details about specific filesystems, and simply executes file system checkers specific to each filesystem type - (/sbin/fsck.type). These checkers will decide if + (fsck.type). These checkers will decide if the filesystem should actually be checked based on the time since last check, number of mounts, unclean unmount, etc. - systemd-fsck-root.service will activate - reboot.target if /sbin/fsck - returns the "System should reboot" condition, or - emergency.target if /sbin/fsck + systemd-fsck-root.service and systemd-fsck-usr.service + will activate reboot.target if fsck returns the "System + should reboot" condition, or emergency.target if fsck returns the "Filesystem errors left uncorrected" condition. systemd-fsck@.service will fail if - /sbin/fsck returns with either "System should reboot" + fsck returns with either "System should reboot" or "Filesystem errors left uncorrected" conditions. For filesystems listed in /etc/fstab without nofail or noauto options, local-fs.target diff --git a/man/systemd-journal-remote.service.xml b/man/systemd-journal-remote.service.xml index e66e0f1e9..c8a702ad5 100644 --- a/man/systemd-journal-remote.service.xml +++ b/man/systemd-journal-remote.service.xml @@ -227,6 +227,7 @@ + Will write to this journal file. The filename @@ -238,6 +239,7 @@ + Will create journal files underneath directory diff --git a/man/systemd-makefs@.service.xml b/man/systemd-makefs@.service.xml index 59c1a1439..1eedb77a8 100644 --- a/man/systemd-makefs@.service.xml +++ b/man/systemd-makefs@.service.xml @@ -19,6 +19,7 @@ systemd-makefs@.service systemd-mkswap@.service systemd-growfs@.service + systemd-growfs-root.service systemd-makefs systemd-growfs Creating and growing file systems on demand @@ -28,6 +29,7 @@ systemd-makefs@device.service systemd-mkswap@device.service systemd-growfs@mountpoint.service + systemd-growfs-root.service /usr/lib/systemd/systemd-makefs /usr/lib/systemd/systemd-growfs @@ -36,8 +38,9 @@ Description systemd-makefs@.service, - systemd-mkswap@.service, and - systemd-growfs@.service are used to implement the + systemd-mkswap@.service, + systemd-growfs@.service, and + systemd-growfs-root.service are used to implement the and options in fstab5, see systemd.mount5. diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml index 46fc97965..3e5ab25ac 100644 --- a/man/systemd-measure.xml +++ b/man/systemd-measure.xml @@ -277,7 +277,7 @@ objcopy1, systemd-creds1, systemd-cryptsetup@.service8, - systemd-pcrphase.service1 + systemd-pcrphase.service8 diff --git a/man/systemd-mount.xml b/man/systemd-mount.xml index 1cde3ab00..e25d5c435 100644 --- a/man/systemd-mount.xml +++ b/man/systemd-mount.xml @@ -227,7 +227,7 @@ This option only has an effect in automount mode, and controls whether the automount unit shall be bound to the backing device's lifetime. If set, the - automount point will be removed automatically when the backing device vanishes. By default the automount point + automount unit will be stopped automatically when the backing device vanishes. By default the automount unit stays around, and subsequent accesses will block until backing device is replugged. This option has no effect in case of non-device mounts, such as network or virtual file system mounts. diff --git a/man/systemd-network-generator.service.xml b/man/systemd-network-generator.service.xml index 2ddeadfc5..13f093646 100644 --- a/man/systemd-network-generator.service.xml +++ b/man/systemd-network-generator.service.xml @@ -95,7 +95,7 @@ See - dracut.kernel7 + dracut.cmdline7 and systemd-udevd.service8 for option syntax and details. diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index a413c9edd..0f2ec2788 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -1657,7 +1657,7 @@ After=sys-subsystem-net-devices-ens1.device # dnf -y --releasever=&fedora_latest_version; --installroot=/var/lib/machines/f&fedora_latest_version; \ --repo=fedora --repo=updates --setopt=install_weak_deps=False install \ - passwd dnf fedora-release vim-minimal systemd systemd-networkd + passwd dnf fedora-release vim-minimal util-linux systemd systemd-networkd # systemd-nspawn -bD /var/lib/machines/f&fedora_latest_version; This installs a minimal Fedora distribution into the diff --git a/man/systemd-random-seed.service.xml b/man/systemd-random-seed.service.xml index a1e31cd46..9f41332af 100644 --- a/man/systemd-random-seed.service.xml +++ b/man/systemd-random-seed.service.xml @@ -23,7 +23,7 @@ systemd-random-seed.service - /usr/lib/systemd/random-seed + /usr/lib/systemd/systemd-random-seed diff --git a/man/systemd-sleep.conf.xml b/man/systemd-sleep.conf.xml index 79ebef1fe..bdc4c3c19 100644 --- a/man/systemd-sleep.conf.xml +++ b/man/systemd-sleep.conf.xml @@ -138,21 +138,24 @@ HibernateMode= HybridSleepMode= - The string to be written to - /sys/power/disk by, - respectively, + The string to be written to /sys/power/disk by, respectively, systemd-suspend.service8, - systemd-hibernate.service8, or + systemd-hibernate.service8, + or systemd-hybrid-sleep.service8. - More than one value can be specified by separating - multiple values with whitespace. They will be tried - in turn, until one is written without error. If - neither succeeds, the operation will be aborted. - + More than one value can be specified by separating multiple values with whitespace. They will be + tried in turn, until one is written without error. If none of the writes succeed, the operation will + be aborted. - systemd-suspend-then-hibernate.service8 - uses the value of SuspendMode= when suspending and the value of HibernateMode= when hibernating. - + The allowed set of values is determined by the kernel and is shown in the file itself (use + cat /sys/power/disk to display). See the + kernel documentation for more details. + + + systemd-suspend-then-hibernate.service8 + uses the value of SuspendMode= when suspending and the value of + HibernateMode= when hibernating. @@ -160,21 +163,25 @@ HibernateState= HybridSleepState= - The string to be written to - /sys/power/state by, - respectively, + The string to be written to /sys/power/state by, respectively, systemd-suspend.service8, - systemd-hibernate.service8, or + systemd-hibernate.service8, + or systemd-hybrid-sleep.service8. - More than one value can be specified by separating - multiple values with whitespace. They will be tried - in turn, until one is written without error. If - neither succeeds, the operation will be aborted. + More than one value can be specified by separating multiple values with whitespace. They will be + tried in turn, until one is written without error. If none of the writes succeed, the operation will + be aborted. - systemd-suspend-then-hibernate.service8 - uses the value of SuspendState= when suspending and the value of HibernateState= when hibernating. - + The allowed set of values is determined by the kernel and is shown in the file itself (use + cat /sys/power/state to display). See the + kernel documentation for more details. + + + systemd-suspend-then-hibernate.service8 + uses the value of SuspendState= when suspending and the value of + HibernateState= when hibernating. @@ -197,7 +204,7 @@ capacity level and estimate battery discharging rate, which is used for estimating timespan until the system battery charge level goes down to 5%. Only used by systemd-suspend-then-hibernate.service8. - Defaults to 2h. + Defaults to 1h. diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index ac21c31d9..2bdfa1c02 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -448,11 +448,11 @@ IPAccounting=. See systemd.resource-control5 for details on the per-unit settings. DefaultTasksAccounting= defaults to yes, - DefaultMemoryAccounting= to - &MEMORY_ACCOUNTING_DEFAULT;. DefaultCPUAccounting= defaults to yes if enabling CPU - accounting doesn't require the CPU controller to be enabled (Linux 4.15+ using the unified hierarchy - for resource control), otherwise it defaults to no. The other three settings default to - no. + DefaultMemoryAccounting= to &MEMORY_ACCOUNTING_DEFAULT;. + DefaultCPUAccounting= defaults to yes, but really has no effect if enabling CPU + accounting doesn't require the controller to be enabled (Linux 4.15+ using the + unified hierarchy for resource control), otherwise it defaults to no. The other three settings + default to no. diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index 92ab322ba..5fd324847 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -142,8 +142,10 @@ - Also execute lines with an exclamation mark. - + Also execute lines with an exclamation mark. Lines that are not safe to be executed + on a running system may be marked in this way. systemd-tmpfiles is executed in + early boot with specified and will execute those lines. When invoked again + later, it should be called without . diff --git a/man/systemd-userdbd.service.xml b/man/systemd-userdbd.service.xml index 9d8b62c45..63673d9dc 100644 --- a/man/systemd-userdbd.service.xml +++ b/man/systemd-userdbd.service.xml @@ -57,7 +57,7 @@ records as acquired with APIs such as getpwnam1 to JSON user/group records, thus hiding the differences between the services as much as - possible. io.systemd.Dropin makes JSON user/group records from the aforementioned + possible. io.systemd.DropIn makes JSON user/group records from the aforementioned drop-in directories available. diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4927764b9..b01165243 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1788,17 +1788,22 @@ BindReadOnlyPaths=/var/lib/systemd ProtectClock= - Takes a boolean argument. If set, writes to the hardware clock or system clock will be denied. - It is recommended to turn this on for most services that do not need modify the clock. Defaults to off. Enabling - this option removes CAP_SYS_TIME and CAP_WAKE_ALARM from the - capability bounding set for this unit, installs a system call filter to block calls that can set the - clock, and DeviceAllow=char-rtc r is implied. This ensures /dev/rtc0, - /dev/rtc1, etc. are made read-only to the service. See + Takes a boolean argument. If set, writes to the hardware clock or system clock will + be denied. Defaults to off. Enabling this option removes CAP_SYS_TIME and + CAP_WAKE_ALARM from the capability bounding set for this unit, installs a system + call filter to block calls that can set the clock, and DeviceAllow=char-rtc r is + implied. Note that the system calls are blocked altogether, the filter does not take into account + that some of the calls can be used to read the clock state with some parameter combinations. + Effectively, /dev/rtc0, /dev/rtc1, etc. are made read-only + to the service. See systemd.resource-control5 - for the details about DeviceAllow=. If this setting is on, but the unit - doesn't have the CAP_SYS_ADMIN capability (e.g. services for which + for the details about DeviceAllow=. If this setting is on, but the unit doesn't + have the CAP_SYS_ADMIN capability (e.g. services for which User= is set), NoNewPrivileges=yes is implied. + It is recommended to turn this on for most services that do not need modify the clock or check + its state. + diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index 19ec586fa..1845d8337 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -103,16 +103,16 @@ normal-dir In normal use this is /run/systemd/generator in case of the system - generators and $XDG_RUNTIME_DIR/generator in case of the user generators. Unit - files placed in this directory take precedence over vendor unit configuration but not over native - user/administrator unit configuration. + generators and $XDG_RUNTIME_DIR/systemd/generator in case of the user + generators. Unit files placed in this directory take precedence over vendor unit configuration but + not over native user/administrator unit configuration. early-dir In normal use this is /run/systemd/generator.early in case of the system - generators and $XDG_RUNTIME_DIR/generator.early in case of the user + generators and $XDG_RUNTIME_DIR/systemd/generator.early in case of the user generators. Unit files placed in this directory override unit files in /usr/, /run/ and /etc/. This means that unit files placed in this directory take precedence over all normal configuration, both vendor and user/administrator. @@ -121,7 +121,7 @@ late-dir In normal use this is /run/systemd/generator.late in case of the system - generators and $XDG_RUNTIME_DIR/generator.late in case of the user + generators and $XDG_RUNTIME_DIR/systemd/generator.late in case of the user generators. This directory may be used to extend the unit file tree without overriding any other unit files. Any native configuration files supplied by the vendor or user/administrator take precedence. diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 266ad52df..4505438d6 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -1711,7 +1711,9 @@ Endpoint= Sets an endpoint IP address or hostname, followed by a colon, and then - a port number. This endpoint will be updated automatically once to + a port number. IPv6 address must be in the square brackets. For example, + 111.222.333.444:51820 for IPv4 and [1111:2222::3333]:51820 + for IPv6 address. This endpoint will be updated automatically once to the most recent source IP address and port of correctly authenticated packets from the peer at configuration time. diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 2a0e40a17..48e7c5296 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -59,10 +59,78 @@ systemd.exec5. Those options complement options listed here. - See the New - Control Group Interfaces for an introduction on how to make - use of resource control APIs from programs. + + Enabling and disabling controllers + + Controllers in the cgroup hierarchy are hierarchical, and resource control is realized by + distributing resource assignments between siblings in branches of the cgroup hierarchy. There is no + need to explicitly enable a cgroup controller for a unit. + systemd will instruct the kernel to enable a controller for a given unit when this + unit has configuration for a given controller. For example, when CPUWeight= is set, + the controller will be enabled, and when TasksMax= are set, the + controller will be enabled. In addition, various controllers may be also be + enabled explicitly via the + MemoryAccounting=/TasksAccounting=/IOAccounting= + settings. Because of how the cgroup hierarchy works, controllers will be automatically enabled for all + parent units and for any sibling units starting with the lowest level at which a controller is enabled. + Units for which a controller is enabled may be subject to resource control even if they don't have any + explicit configuration. + + Setting Delegate= enables any delegated controllers for that unit (see below). + The delegatee may then enable controllers for its children as appropriate. In particular, if the + delegatee is systemd (in the user@.service unit), it will + repeat the same logic as the system instance and enable controllers for user units which have resource + limits configured, and their siblings and parents and parents' siblings. + + Controllers may be disabled for parts of the cgroup hierarchy with + DisableControllers= (see below). + + + Enabling and disabling controllers + + + -.slice + / \ + /-----/ \--------------\ + / \ + system.slice user.slice + / \ / \ + / \ / \ + / \ user@42.service user@1000.service + / \ Delegate= Delegate=yes +a.service b.slice / \ +CPUWeight=20 DisableControllers=cpu / \ + / \ app.slice session.slice + / \ CPUWeight=100 CPUWeight=100 + / \ + b1.service b2.service + CPUWeight=1000 + + + In this hierarchy, the controller is enabled for all units shown except + b1.service and b2.service. Because there is no explicit + configuration for system.slice and user.slice, CPU + resources will be split equally between them. Similarly, resources are allocated equally between + children of user.slice and between the child slices beneath + user@1000.service. Assuming that there is no futher configuration of resources + or delegation below slices app.slice or session.slice, the + controller would not be enabled for units in those slices and CPU resources + would be further allocated using other mechanisms, e.g. based on nice levels. The manager for user + 42 has delegation enabled without any controllers, i.e. it can manipulate its subtree of the cgroup + hierarchy, but without resource control. + + In the slice system.slice, CPU resources are split 1:6 for service + a.service, and 5:6 for slice b.slice, because slice + b.slice gets the default value of 100 for cpu.weight when + CPUWeight= is not set. + + CPUWeight= setting in service b2.service is neutralized + by DisableControllers= in slice b.slice, so the + controller would not be enabled for services b1.service and + b2.service, and CPU resources would be further allocated using other mechanisms, + e.g. based on nice levels. + + Setting resource controls for a group of related units @@ -82,6 +150,11 @@ /etc/systemd/system/user-.slice.d/*.conf. This last directory applies to all user slices. + + See the New + Control Group Interfaces for an introduction on how to make + use of resource control APIs from programs. @@ -118,6 +191,9 @@ setting may be controlled with DefaultCPUAccounting= in systemd-system.conf5. + + Under the unified cgroup hierarchy, CPU accounting is available for all units and this + setting has no effect. @@ -126,17 +202,20 @@ StartupCPUWeight=weight + These settings control the controller in the unified hierarchy. + These options accept an integer value or a the special string "idle": - 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 - cpu.weight control group attribute. The allowed range is 1 to 10000. Defaults to - 100. For details about this control group attribute, see Control Groups v2 - and CFS - Scheduler. 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. + 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 cpu.weight control group attribute. The allowed range is 1 to 10000. + Defaults to unset, but the kernel default is 100. For details about this control group + attribute, see Control Groups + v2 and CFS + Scheduler. 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. If set to the special string "idle", mark the cgroup for "idle scheduling", which means @@ -151,6 +230,13 @@ CPUWeight= applies to normal runtime of the system, and if the former is not set also to the startup and shutdown phases. Using StartupCPUWeight= allows prioritizing specific services at boot-up and shutdown differently than during normal runtime. + + In addition to the resource allocation performed by the controller, the + kernel may automatically divide resources based on session-id grouping, see "The autogroup feature" + in sched7. + The effect of this feature is similar to the controller with no explicit + configuration, so users should be careful to not mistake one for the other. @@ -158,6 +244,8 @@ CPUQuota= + This setting controls the controller in the unified hierarchy. + Assign the specified CPU time quota to the processes executed. Takes a percentage value, suffixed with "%". The percentage specifies how much CPU time the unit shall get at maximum, relative to the total CPU time available on one CPU. Use values > 100% for allotting CPU time on more than one CPU. This controls the @@ -177,6 +265,8 @@ CPUQuotaPeriodSec= + This setting controls the controller in the unified hierarchy. + Assign the duration over which the CPU time quota specified by CPUQuota= is measured. Takes a time duration value in seconds, with an optional suffix such as "ms" for milliseconds (or "s" for seconds.) The default setting is 100ms. The period is clamped to the range supported by the kernel, which is [1ms, 1000ms]. @@ -197,6 +287,8 @@ StartupAllowedCPUs= + This setting controls the controller in the unified hierarchy. + Restrict processes to be executed on specific CPUs. Takes a list of CPU indices or ranges separated by either whitespace or commas. CPU ranges are specified by the lower and upper CPU indices separated by a dash. @@ -218,6 +310,8 @@ StartupAllowedMemoryNodes= + These settings control the controller in the unified hierarchy. + Restrict processes to be executed on specific memory NUMA nodes. Takes a list of memory NUMA nodes indices or ranges separated by either whitespace or commas. Memory NUMA nodes ranges are specified by the lower and upper NUMA nodes indices separated by a dash. @@ -239,6 +333,8 @@ MemoryAccounting= + This setting controls the controller in the unified hierarchy. + Turn on process and kernel memory accounting for this unit. Takes a boolean argument. Note that turning on memory accounting for one unit will also implicitly turn it on for @@ -254,6 +350,8 @@ MemoryMin=bytes, MemoryLow=bytes + These settings control the controller in the unified hierarchy. + Specify the memory usage protection of the executed processes in this unit. When reclaiming memory, the unit is treated as if it was using less memory resulting in memory to be preferentially reclaimed from unprotected units. @@ -291,6 +389,8 @@ MemoryHigh=bytes + These settings control the controller in the unified hierarchy. + Specify the throttling limit on memory usage of the executed processes in this unit. Memory usage may go above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away aggressively in such cases. This is the main mechanism to control memory usage of a unit. @@ -309,6 +409,8 @@ MemoryMax=bytes + These settings control the controller in the unified hierarchy. + Specify the absolute limit on memory usage of the executed processes in this unit. If memory usage cannot be contained under the limit, out-of-memory killer is invoked inside the unit. It is recommended to use MemoryHigh= as the main control mechanism and use MemoryMax= as the @@ -327,6 +429,8 @@ MemorySwapMax=bytes + These settings control the controller in the unified hierarchy. + Specify the absolute limit on swap usage of the executed processes in this unit. Takes a swap size in bytes. If the value is suffixed with K, M, G or T, the specified swap size is @@ -341,17 +445,14 @@ TasksAccounting= - Turn on task accounting for this unit. Takes a - boolean argument. If enabled, the system manager will keep - track of the number of tasks in the unit. The number of - tasks accounted this way includes both kernel threads and - userspace processes, with each thread counting - individually. Note that turning on tasks accounting for one - unit will also implicitly turn it on for all units contained - in the same slice and for all its parent slices and the - units contained therein. The system default for this setting - may be controlled with - DefaultTasksAccounting= in + This setting controls the controller in the unified hierarchy. + + Turn on task accounting for this unit. Takes a boolean argument. If enabled, the kernel will + keep track of the total number of tasks in the unit and its children. This number includes both + kernel threads and userspace processes, with each thread counted individually. Note that turning on + tasks accounting for one unit will also implicitly turn it on for all units contained in the same + slice and for all its parent slices and the units contained therein. The system default for this + setting may be controlled with DefaultTasksAccounting= in systemd-system.conf5. @@ -360,6 +461,8 @@ TasksMax=N + This setting controls the controller in the unified hierarchy. + Specify the maximum number of tasks that may be created in the unit. This ensures that the number of tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number of tasks or a percentage value that is taken relative to the configured maximum @@ -379,6 +482,8 @@ IOAccounting= + This setting controls the controller in the unified hierarchy. + Turn on Block I/O accounting for this unit, if the unified control group hierarchy is used on the system. Takes a boolean argument. Note that turning on block I/O accounting for one unit will also implicitly turn it on for all units contained in the same slice and all for its parent slices and the units contained @@ -393,6 +498,8 @@ StartupIOWeight=weight + These settings control the controller in the unified hierarchy. + Set the default overall block I/O weight for the executed processes, if the unified control group hierarchy is used on the system. Takes a single weight value (between 1 and 10000) to set the default block I/O weight. This controls the io.weight control group attribute, @@ -415,6 +522,8 @@ IODeviceWeight=device weight + This setting controls the controller in the unified hierarchy. + Set the per-device overall block I/O weight for the executed processes, if the unified control group hierarchy is used on the system. Takes a space-separated pair of a file path and a weight value to specify the device specific weight value, between 1 and 10000. (Example: /dev/sda 1000). The file @@ -439,6 +548,8 @@ IOWriteBandwidthMax=device bytes + These settings control the controller in the unified hierarchy. + Set the per-device overall block I/O bandwidth maximum limit for the executed processes, if the unified control group hierarchy is used on the system. This limit is not work-conserving and the executed processes are not allowed to use more even if the device has idle capacity. Takes a space-separated pair of a file @@ -461,6 +572,8 @@ IOWriteIOPSMax=device IOPS + These settings control the controller in the unified hierarchy. + Set the per-device overall block I/O IOs-Per-Second maximum limit for the executed processes, if the unified control group hierarchy is used on the system. This limit is not work-conserving and the executed processes are not allowed to use more even if the device has idle capacity. Takes a space-separated pair of @@ -482,6 +595,8 @@ IODeviceLatencyTargetSec=device target + This setting controls the controller in the unified hierarchy. + Set the per-device average target I/O latency for the executed processes, if the unified control group hierarchy is used on the system. Takes a file path and a timespan separated by a space to specify the device specific latency target. (Example: "/dev/sda 25ms"). The file path may be specified @@ -976,29 +1091,37 @@ DeviceAllow=/dev/loop-control Turns on delegation of further resource control partitioning to processes of the unit. Units where this is enabled may create and manage their own private subhierarchy of control groups below the control group of the unit itself. For unprivileged services (i.e. those using the User= setting) the unit's - control group will be made accessible to the relevant user. When enabled the service manager will refrain - from manipulating control groups or moving processes below the unit's control group, so that a clear concept - of ownership is established: the control group tree above the unit's control group (i.e. towards the root - control group) is owned and managed by the service manager of the host, while the control group tree below - the unit's control group is owned and managed by the unit itself. Takes either a boolean argument or a list - of control group controller names. If true, delegation is turned on, and all supported controllers are - enabled for the unit, making them available to the unit's processes for management. If false, delegation is - turned off entirely (and no additional controllers are enabled). If set to a list of controllers, delegation - is turned on, and the specified controllers are enabled for the unit. Note that additional controllers than - the ones specified might be made available as well, depending on configuration of the containing slice unit - or other units contained in it. Note that assigning the empty string will enable delegation, but reset the - list of controllers, all assignments prior to this will have no effect. Defaults to false. + control group will be made accessible to the relevant user. - Note that controller delegation to less privileged code is only safe on the unified control group - hierarchy. Accordingly, access to the specified controllers will not be granted to unprivileged services on - the legacy hierarchy, even when requested. + When enabled the service manager will refrain from manipulating control groups or moving + processes below the unit's control group, so that a clear concept of ownership is established: the + control group tree at the level of the unit's control group and above (i.e. towards the root + control group) is owned and managed by the service manager of the host, while the control group + tree below the unit's control group is owned and managed by the unit itself. + + Takes either a boolean argument or a (possibly empty) list of control group controller names. + If true, delegation is turned on, and all supported controllers are enabled for the unit, making + them available to the unit's processes for management. If false, delegation is turned off entirely + (and no additional controllers are enabled). If set to a list of controllers, delegation is turned + on, and the specified controllers are enabled for the unit. Assigning the empty string will enable + delegation, but reset the list of controllers, and all assignments prior to this will have no + effect. Note that additional controllers other than the ones specified might be made available as + well, depending on configuration of the containing slice unit or other units contained in it. + Defaults to false. + + Note that controller delegation to less privileged code is only safe on the unified control + group hierarchy. Accordingly, access to the specified controllers will not be granted to + unprivileged services on the legacy hierarchy, even when requested. - Not all of these controllers are available on all kernels however, and some are - specific to the unified hierarchy while others are specific to the legacy hierarchy. Also note that the - kernel might support further controllers, which aren't covered here yet as delegation is either not supported - at all for them or not defined cleanly. + Not all of these controllers are available on all kernels however, and some are specific to + the unified hierarchy while others are specific to the legacy hierarchy. Also note that the kernel + might support further controllers, which aren't covered here yet as delegation is either not + supported at all for them or not defined cleanly. + + Note that because of the hierarchical nature of cgroup hierarchy, any controllers that are + delegated will be enabled for the parent and sibling units of the unit with delegation. For further details on the delegation model consult Control Group APIs and Delegation. @@ -1009,19 +1132,20 @@ DeviceAllow=/dev/loop-control DisableControllers= - Disables controllers from being enabled for a unit's children. If a controller listed is already in use - in its subtree, the controller will be removed from the subtree. This can be used to avoid child units being - able to implicitly or explicitly enable a controller. Defaults to not disabling any controllers. - - It may not be possible to successfully disable a controller if the unit or any child of the unit in - question delegates controllers to its children, as any delegated subtree of the cgroup hierarchy is unmanaged - by systemd. + Disables controllers from being enabled for a unit's children. If a controller listed is + already in use in its subtree, the controller will be removed from the subtree. This can be used to + avoid configuration in child units from being able to implicitly or explicitly enable a controller. + Defaults to empty. Multiple controllers may be specified, separated by spaces. You may also pass DisableControllers= multiple times, in which case each new instance adds another controller to disable. Passing DisableControllers= by itself with no controller name present resets the disabled controller list. + It may not be possible to disable a controller after units have been started, if the unit or + any child of the unit in question delegates controllers to its children, as any delegated subtree + of the cgroup hierarchy is unmanaged by systemd. + diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 6d3537be7..083ad106a 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -907,8 +907,7 @@ limiting configured with StartLimitIntervalSec= and StartLimitBurst=, see systemd.unit5 - for details. A restarted service enters the failed state only - after the start limits are reached. + for details. Setting this to is the recommended choice for long-running services, in order to diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 0c17d9181..7311dcb36 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -110,19 +110,19 @@ Unit files are loaded from a set of paths determined during compilation, described in the next section. - Valid unit names consist of a "name prefix" and a dot and a suffix specifying the unit type. The - "unit prefix" must consist of one or more valid characters (ASCII letters, digits, :, - -, _, ., and \). The total - length of the unit name including the suffix must not exceed 256 characters. The type suffix must be one - of .service, .socket, .device, - .mount, .automount, .swap, - .target, .path, .timer, - .slice, or .scope. + Valid unit names consist of a "unit name prefix", and a suffix specifying the unit type which + begins with a dot. The "unit name prefix" must consist of one or more valid characters (ASCII letters, + digits, :, -, _, ., and + \). The total length of the unit name including the suffix must not exceed 255 + characters. The unit type suffix must be one of .service, .socket, + .device, .mount, .automount, + .swap, .target, .path, + .timer, .slice, or .scope. - Units names can be parameterized by a single argument called the "instance name". The unit is then + Unit names can be parameterized by a single argument called the "instance name". The unit is then constructed based on a "template file" which serves as the definition of multiple services or other - units. A template unit must have a single @ at the end of the name (right before the - type suffix). The name of the full unit is formed by inserting the instance name between + units. A template unit must have a single @ at the end of the unit name prefix (right + before the type suffix). The name of the full unit is formed by inserting the instance name between @ and the unit type suffix. In the unit file itself, the instance parameter may be referred to using %i and other specifiers, see below. @@ -823,8 +823,7 @@ OnFailure= A space-separated list of one or more units that are activated when this unit enters - the failed state. A service unit using Restart= enters the - failed state only after the start limits are reached. + the failed state. @@ -1602,14 +1601,23 @@ ConditionControlGroupController= Check whether given cgroup controllers (e.g. cpu) are available - for use on the system. + for use on the system or whether the legacy v1 cgroup or the modern v2 cgroup hierarchy is used. + Multiple controllers may be passed with a space separating them; in this case the condition will only pass if all listed controllers are available for use. Controllers unknown to systemd are - ignored. Valid controllers are cpu, cpuset, - io, memory, and pids. Even if available in - the kernel, a particular controller may not be available if it was disabled on the kernel command - line with cgroup_disable=controller. + ignored. Valid controllers are cpu, io, + memory, and pids. Even if available in the kernel, a + particular controller may not be available if it was disabled on the kernel command line with + cgroup_disable=controller. + + Alternatively, two special strings v1 and v2 may be + specified (without any controller names). v2 will pass if the unified v2 cgroup + hierarchy is used, and v1 will pass if the legacy v1 hierarchy or the hybrid + hierarchy are used. Note that legacy or hybrid hierarchies have been deprecated. See + systemd1 for + more information. + diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index d37e05e55..4e92334b8 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -644,7 +644,7 @@ w- /proc/sys/vm/swappiness - - - - 10 For example: # Files created and modified, and directories accessed more than # an hour ago in "/tmp/foo/bar", are subject to time-based cleanup. -d /tmp/foo/bar - - - - bmA:1h - +d /tmp/foo/bar - - - bmA:1h - Note that while the aging algorithm is run a 'shared' BSD file lock (see flock2) is diff --git a/man/udev.xml b/man/udev.xml index 142f295f3..332c7ac09 100644 --- a/man/udev.xml +++ b/man/udev.xml @@ -186,10 +186,10 @@ SYMLINK - Match the name of a symlink targeting the node. It can - be used once a SYMLINK key has been set in one of the preceding - rules. There may be multiple symlinks; only one needs to match. - + Match the name of a symlink targeting the node. It can be used once a SYMLINK key has + been set in one of the preceding rules. There may be multiple symlinks; only one needs to + match. If the operator is !=, the token returns true only if there is no + symlink matched. @@ -287,14 +287,17 @@ TAG - Match against a device tag. + Match against one of device tags. It can be used once a TAG key has been set in one of + the preceding rules. There may be multiple tags; only one needs to match. If the operator is + !=, the token returns true only if there is no tag matched. TAGS - Search the devpath upwards for a device with matching tag. + Search the devpath upwards for a device with matching tag. If the operator is + !=, the token returns true only if there is no tag matched. diff --git a/meson.build b/meson.build index 35704947e..616493ea7 100644 --- a/meson.build +++ b/meson.build @@ -510,6 +510,7 @@ conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include freq)', prefix : '#include ')) decl_headers = ''' +#include #include #include #include @@ -519,6 +520,7 @@ foreach decl : ['char16_t', 'char32_t', 'struct mount_attr', 'struct statx', + 'struct dirent64', ] # We get -1 if the size cannot be determined @@ -742,6 +744,7 @@ foreach header : ['crypt.h', 'linux/memfd.h', 'linux/vm_sockets.h', 'sys/auxv.h', + 'threads.h', 'valgrind/memcheck.h', 'valgrind/valgrind.h', 'linux/time_types.h', diff --git a/meson_options.txt b/meson_options.txt index 814f34084..26dfab5ce 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -18,7 +18,7 @@ option('rootlibdir', type : 'string', option('rootprefix', type : 'string', description : '''override the root prefix [default '/' if split-usr and '/usr' otherwise]''') option('link-udev-shared', type : 'boolean', - description : 'link systemd-udev and its helpers to libsystemd-shared.so') + description : 'link systemd-udevd and its helpers to libsystemd-shared.so') option('link-systemctl-shared', type: 'boolean', description : 'link systemctl against libsystemd-shared.so') option('link-networkd-shared', type: 'boolean', diff --git a/rules.d/60-persistent-storage.rules b/rules.d/60-persistent-storage.rules index 18588e4c4..d6612daf7 100644 --- a/rules.d/60-persistent-storage.rules +++ b/rules.d/60-persistent-storage.rules @@ -37,14 +37,22 @@ KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_S KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{wwid}=="?*", ENV{ID_WWN}="$attr{wwid}" KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}" KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{firmware_rev}=="?*", ENV{ID_REVISION}="$attr{firmware_rev}" +KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{nsid}=="?*", ENV{ID_NSID}="$attr{nsid}" +# obsolete symlink that might get overridden on adding a new nvme controller, kept for backward compatibility KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", \ OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" +KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_NSID}=="?*",\ + OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}_$env{ID_NSID}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}" KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{firmware_rev}=="?*", ENV{ID_REVISION}="$attr{firmware_rev}" +KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{nsid}=="?*", ENV{ID_NSID}="$attr{nsid}" +# obsolete symlink that might get overridden on adding a new nvme controller, kept for backward compatibility KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", \ OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" +KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_NSID}=="?*",\ + OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}_$env{ID_NSID}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" # virtio-blk KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" diff --git a/shell-completion/bash/busctl b/shell-completion/bash/busctl index cebd25a87..84bd67cbf 100644 --- a/shell-completion/bash/busctl +++ b/shell-completion/bash/busctl @@ -86,7 +86,7 @@ _busctl() { --show-machine --unique --acquired --activatable --list -q --quiet --verbose --expect-reply=no --auto-start=no --allow-interactive-authorization=no --augment-creds=no - --watch-bind=yes -j -l --full' + --watch-bind=yes -j -l --full --xml-interface' [ARG]='--address -H --host -M --machine --match --timeout --size --json --destination' ) diff --git a/shell-completion/bash/coredumpctl b/shell-completion/bash/coredumpctl index 5416e9e58..b5719905f 100644 --- a/shell-completion/bash/coredumpctl +++ b/shell-completion/bash/coredumpctl @@ -40,23 +40,23 @@ _coredumpctl() { local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} local OPTS='-h --help --version --no-pager --no-legend -o --output -F --field -1 -r --reverse -S --since -U --until -D --directory -q --quiet --debugger - -A --debugger-arguments --json -n --all' + -A --debugger-arguments --json -n --all --file --root --image' local -A VERBS=( [LIST]='list info' [DUMP]='dump debug' ) - if __contains_word "$prev" '--output -o'; then + if __contains_word "$prev" --output -o --file --image; then comps=$( compgen -A file -- "$cur" ) compopt -o filenames - elif __contains_word "$prev" '-D --directory'; then + elif __contains_word "$prev" -D --directory --root; then comps=$( compgen -A directory -- "$cur" ) compopt -o filenames elif __contains_word "$prev" '--debugger'; then comps=$( compgen -A command -- "$cur" ) compopt -o filenames - elif __contains_word "$prev" '--field -F'; then + elif __contains_word "$prev" --field -F; then comps=$( compgen -W '${__journal_fields[*]}' -- "$cur" ) elif __contains_word "$prev" '--json'; then comps=$( compgen -W 'pretty short off' -- "$cur" ) diff --git a/shell-completion/bash/portablectl b/shell-completion/bash/portablectl index 71789277b..519c5c0cd 100644 --- a/shell-completion/bash/portablectl +++ b/shell-completion/bash/portablectl @@ -36,7 +36,7 @@ _portablectl() { local -A OPTS=( [STANDALONE]='-q --quiet --runtime --no-reload --cat --no-pager --no-legend --no-ask-password --enable --now -h --help --version' - [ARG]='-p --profile --copy -H --host -M --machine' + [ARG]='-p --profile --copy -H --host -M --machine --extension' ) local -A VERBS=( @@ -60,6 +60,10 @@ _portablectl() { --machine|-M) comps=$( __get_machines ) ;; + --extension) + comps=$( compgen -A file -- "$cur" ) + compopt -o filenames + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl index 0cb1c44a4..b0cd4d5db 100644 --- a/shell-completion/zsh/_busctl +++ b/shell-completion/zsh/_busctl @@ -276,6 +276,7 @@ _arguments \ '--list[Do not show tree, but simple object path list]' \ {-q,--quiet}'[Do not show method call reply]'\ '--verbose[Show result values in long format]' \ + '--xml-interface[Dump the XML description in introspect command]' \ '--json=[Show result values in long format]:format:_busctl_get_json' \ '-j[Show pretty json in interactive sessions, short json otherwise]' \ '--expect-reply=[Expect a method call reply]:boolean:(1 0)' \ diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index d47174303..2c738498f 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -28,6 +28,8 @@ "show:Show properties of one or more units/jobs or the manager" "cat:Show the source unit files and drop-ins" "set-property:Sets one or more properties of a unit" + "service-log-level:Get or set the logging threshold for service" + "service-log-target:Get or set the logging target for service" "help:Show documentation for specified units" "reset-failed:Reset failed state for all, one, or more units" "list-dependencies:Show unit dependency tree" @@ -159,8 +161,8 @@ __systemctl() if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS$_sys_service_mgr ) || ! _retrieve_cache SYS_ALL_UNITS$_sys_service_mgr; then - _sys_all_units=( ${${(f)"$(__systemctl list-units --all "$PREFIX*" )"}%% *} ) - _store_cache SYS_ALL_UNITS$_sys_service_mgr _sys_all_units + _sys_all_units=( ${${(f)"$(__systemctl list-units --all)"}%% *} ) + _store_cache SYS_ALL_UNITS$_sys_service_mgr _sys_all_unis fi } @@ -173,7 +175,7 @@ __systemctl() if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS$_sys_service_mgr ) || ! _retrieve_cache SYS_REALLY_ALL_UNITS$_sys_service_mgr; then - all_unit_files=( ${${(f)"$(__systemctl list-unit-files "$PREFIX*" )"}%% *} ) + all_unit_files=( ${${(f)"$(__systemctl list-unit-files)"}%% *} ) _systemctl_all_units really_all_units=($_sys_all_units $all_unit_files) _sys_really_all_units=(${(u)really_all_units}) @@ -192,22 +194,22 @@ __systemctl() (( $+functions[_systemctl_get_non_template_names] )) || _systemctl_get_non_template_names() { echo -E - ${^${(R)${(f)"$( - __systemctl list-unit-files "$PREFIX*" - __systemctl list-units --all "$PREFIX*" + __systemctl list-unit-files + __systemctl list-units --all )"}:#*@.*}%%[[:space:]]*} } (( $+functions[_systemctl_get_template_names] )) || - _systemctl_get_template_names() { echo -E - ${^${(M)${(f)"$(__systemctl list-unit-files "$PREFIX*" )"}##*@.[^[:space:]]##}%%@.*}\@ } + _systemctl_get_template_names() { echo -E - ${^${(M)${(f)"$(__systemctl list-unit-files)"}##*@.[^[:space:]]##}%%@.*}\@ } (( $+functions[_systemctl_active_units] )) || - _systemctl_active_units() {_sys_active_units=( ${${(f)"$(__systemctl list-units "$PREFIX*" )"}%% *} )} + _systemctl_active_units() {_sys_active_units=( ${${(f)"$(__systemctl list-units)"}%% *} )} (( $+functions[_systemctl_startable_units] )) || _systemctl_startable_units(){ _sys_startable_units=( $( _filter_units_by_property ActiveState inactive $( _filter_units_by_property CanStart yes ${${${(f)"$( - __systemctl list-unit-files --state enabled,enabled-runtime,linked,linked-runtime,static,indirect,disabled,generated,transient "$PREFIX*" - __systemctl list-units --state inactive,failed "$PREFIX*" + __systemctl list-unit-files --state enabled,enabled-runtime,linked,linked-runtime,static,indirect,disabled,generated,transient + __systemctl list-units --state inactive,failed )"}:#*@.*}%%[[:space:]]*} )) ) } @@ -215,19 +217,19 @@ __systemctl() (( $+functions[_systemctl_restartable_units] )) || _systemctl_restartable_units(){ _sys_restartable_units=( $( _filter_units_by_property CanStart yes ${${${(f)"$( - __systemctl list-unit-files --state enabled,disabled,static "$PREFIX*" - __systemctl list-units "$PREFIX*" + __systemctl list-unit-files --state enabled,disabled,static + __systemctl list-units )"}:#*@.*}%%[[:space:]]*} ) ) } (( $+functions[_systemctl_failed_units] )) || - _systemctl_failed_units() {_sys_failed_units=( ${${(f)"$(__systemctl list-units --state=failed "$PREFIX*" )"}%% *} ) } + _systemctl_failed_units() {_sys_failed_units=( ${${(f)"$(__systemctl list-units --state=failed)"}%% *} ) } (( $+functions[_systemctl_unit_state] )) || _systemctl_unit_state() { setopt localoptions extendedglob typeset -gA _sys_unit_state - _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files "$PREFIX*" )"}%%[[:space:]]#}% *} ) + _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files)"}%%[[:space:]]#}% *} ) } local fun @@ -300,6 +302,30 @@ for fun in stop kill try-restart condrestart ; do } done +(( $+functions[_systemctl_service-log-level] )) || + _systemctl_service-log-level() { + local -a log_levels=( emerg alert crit err warning notice info debug ) + local _sys_active_units; _systemctl_active_units + if (( CURRENT == 2 )); then + _wanted systemd-units expl 'active unit' \ + compadd "$@" -a - _sys_active_units || _message "no units found" + else + compadd "$@" -a - log_levels + fi +} + +(( $+functions[_systemctl_service-log-target] )) || + _systemctl_service-log-target() { + local -a log_targets=( console kmsg journal syslog null auto ) + local _sys_active_units; _systemctl_active_units + if (( CURRENT == 2 )); then + _wanted systemd-units expl 'active unit' \ + compadd "$@" -a - _sys_active_units || _message "no units found" + else + compadd "$@" -a - log_targets + fi +} + # Completion functions for ISOLATABLE_UNITS (( $+functions[_systemctl_isolate] )) || _systemctl_isolate() { @@ -350,7 +376,7 @@ done (( $+functions[_systemctl_set-default] )) || _systemctl_set-default() { _wanted systemd-targets expl target \ - compadd "$@" - ${${(f)"$(__systemctl list-unit-files --type target --all "$PREFIX*" )"}%% *} || + compadd "$@" - ${${(f)"$(__systemctl list-unit-files --type target --all)"}%% *} || _message "no targets found" } diff --git a/shell-completion/zsh/_timedatectl b/shell-completion/zsh/_timedatectl index 2dadb65db..2467b80bc 100644 --- a/shell-completion/zsh/_timedatectl +++ b/shell-completion/zsh/_timedatectl @@ -36,6 +36,8 @@ _timedatectl_command(){ 'set-time:Set system time' 'set-timezone:Set system timezone' 'list-timezones:Show known timezones' + 'timesync-status:Show status of systemd-timesyncd' + 'show-timesync:Show properties of systemd-timesyncd' 'set-local-rtc:Control whether RTC is in local time' 'set-ntp:Control whether NTP is enabled' ) diff --git a/src/activate/activate.c b/src/activate/activate.c index 24ebde028..0a16a4333 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -76,6 +76,9 @@ static int open_sockets(int *epoll_fd, bool accept) { except[i] = SD_LISTEN_FDS_START + i; log_close(); + log_set_open_when_needed(true); + log_settle_target(); + r = close_all_fds(except, n); if (r < 0) return log_error_errno(r, "Failed to close all file descriptors: %m"); @@ -88,17 +91,17 @@ static int open_sockets(int *epoll_fd, bool accept) { STRV_FOREACH(address, arg_listen) { r = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept * SOCK_CLOEXEC)); - if (r < 0) { - log_open(); + if (r < 0) return log_error_errno(r, "Failed to open '%s': %m", *address); - } assert(r == SD_LISTEN_FDS_START + count); count++; } - if (arg_listen) + if (arg_listen) { log_open(); + log_set_open_when_needed(false); + } *epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (*epoll_fd < 0) @@ -341,6 +344,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0) switch (c) { case 'h': diff --git a/src/analyze/analyze-syscall-filter.c b/src/analyze/analyze-syscall-filter.c index 308b1724e..f20e4a8e2 100644 --- a/src/analyze/analyze-syscall-filter.c +++ b/src/analyze/analyze-syscall-filter.c @@ -58,17 +58,38 @@ static int load_kernel_syscalls(Set **ret) { return 0; } +static int syscall_set_add(Set **s, const SyscallFilterSet *set) { + const char *sc; + int r; + + assert(s); + + if (!set) + return 0; + + NULSTR_FOREACH(sc, set->value) { + if (sc[0] == '@') + continue; + + r = set_put_strdup(s, sc); + if (r < 0) + return r; + } + + return 0; +} + static void syscall_set_remove(Set *s, const SyscallFilterSet *set) { - const char *syscall; + const char *sc; if (!set) return; - NULSTR_FOREACH(syscall, set->value) { - if (syscall[0] == '@') + NULSTR_FOREACH(sc, set->value) { + if (sc[0] == '@') continue; - free(set_remove(s, syscall)); + free(set_remove(s, sc)); } } @@ -88,17 +109,17 @@ static void dump_syscall_filter(const SyscallFilterSet *set) { int verb_syscall_filters(int argc, char *argv[], void *userdata) { bool first = true; + int r; pager_open(arg_pager_flags); if (strv_isempty(strv_skip(argv, 1))) { _cleanup_set_free_ Set *kernel = NULL, *known = NULL; - const char *sys; int k = 0; /* explicit initialization to appease gcc */ - NULSTR_FOREACH(sys, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value) - if (set_put_strdup(&known, sys) < 0) - return log_oom(); + r = syscall_set_add(&known, syscall_filter_sets + SYSCALL_FILTER_SET_KNOWN); + if (r < 0) + return log_error_errno(r, "Failed to prepare set of known system calls: %m"); if (!arg_quiet) k = load_kernel_syscalls(&kernel); diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index 093533182..d3b61e1bb 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -107,6 +107,10 @@ static int parse_argv(int argc, char *argv[]) { /* Note the asymmetry: the long option --echo= allows an optional argument, the short option does * not. */ + + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+hen", options, NULL)) >= 0) switch (c) { diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index 1bf88b1e5..f2dce206b 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include @@ -12,6 +13,7 @@ #include "macro.h" #include "parse-util.h" #include "process-util.h" +#include "socket-util.h" #include "user-util.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { @@ -68,8 +70,50 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) { return 0; } +static int try_audit_request(int fd) { + struct iovec iov; + struct msghdr mh; + ssize_t n; + + assert(fd >= 0); + + struct { + struct nlmsghdr hdr; + struct nlmsgerr err; + } _packed_ msg = { + .hdr.nlmsg_len = NLMSG_LENGTH(0), + .hdr.nlmsg_type = AUDIT_GET_FEATURE, + .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + }; + iov = (struct iovec) { + .iov_base = &msg, + .iov_len = msg.hdr.nlmsg_len, + }; + mh = (struct msghdr) { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0) + return -errno; + + iov.iov_len = sizeof(msg); + + n = recvmsg_safe(fd, &mh, 0); + if (n < 0) + return -errno; + if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr))) + return -EIO; + + if (msg.hdr.nlmsg_type != NLMSG_ERROR) + return -EINVAL; + + return msg.err.error; +} + bool use_audit(void) { static int cached_use = -1; + int r; if (cached_use < 0) { int fd; @@ -80,7 +124,22 @@ bool use_audit(void) { if (!cached_use) log_debug_errno(errno, "Won't talk to audit: %m"); } else { - cached_use = true; + /* If we try and use the audit fd but get -ECONNREFUSED, it is because + * we are not in the initial user namespace, and the kernel does not + * have support for audit outside of the initial user namespace + * (see https://elixir.bootlin.com/linux/latest/C/ident/audit_netlink_ok). + * + * If we receive any other error, do not disable audit because we are not + * sure that the error indicates that audit will not work in general. */ + r = try_audit_request(fd); + if (r < 0) { + cached_use = r != -ECONNREFUSED; + log_debug_errno(r, cached_use ? + "Failed to make request on audit fd, ignoring: %m" : + "Won't talk to audit: %m"); + } else + cached_use = true; + safe_close(fd); } } diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index fa74b5b9c..df04d461a 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -13,6 +13,7 @@ #include "log.h" #include "macro.h" #include "missing_prctl.h" +#include "missing_threads.h" #include "parse-util.h" #include "user-util.h" #include "util.h" diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 17c0170b8..0b4731f05 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -23,6 +23,7 @@ #include "login-util.h" #include "macro.h" #include "missing_magic.h" +#include "missing_threads.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/basic/coverage.h b/src/basic/coverage.h index 640bddc48..3e674a8db 100644 --- a/src/basic/coverage.h +++ b/src/basic/coverage.h @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +extern void __gcov_dump(void); +extern void __gcov_reset(void); + /* When built with --coverage (gcov) we need to explicitly call __gcov_dump() * in places where we use _exit(), since _exit() skips at-exit hooks resulting * in lost coverage. @@ -8,12 +11,37 @@ * To make sure we don't miss any _exit() calls, this header file is included * explicitly on the compiler command line via the -include directive (only * when built with -Db_coverage=true) - * */ + */ extern void _exit(int); -extern void __gcov_dump(void); static inline _Noreturn void _coverage__exit(int status) { __gcov_dump(); _exit(status); } #define _exit(x) _coverage__exit(x) + +/* gcov provides wrappers for the exec*() calls but there's none for execveat(), + * which means we lose all coverage prior to the call. To mitigate this, let's + * add a simple execveat() wrapper in gcov's style[0], which dumps and resets + * the coverage data when needed. + * + * This applies only when we're built with -Dfexecve=true. + * + * [0] https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/libgcov-interface.c;h=b2ee930864183b78c8826255183ca86e15e21ded;hb=HEAD + */ + +extern int execveat(int, const char *, char * const [], char * const [], int); + +static inline int _coverage_execveat( + int dirfd, + const char *pathname, + char * const argv[], + char * const envp[], + int flags) { + __gcov_dump(); + int r = execveat(dirfd, pathname, argv, envp, flags); + __gcov_reset(); + + return r; +} +#define execveat(d,p,a,e,f) _coverage_execveat(d, p, a, e, f) diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 5fde9043a..d2ac256a4 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -35,6 +35,7 @@ struct dirent *readdir_no_dot(DIR *dirp); /* Only if 64bit off_t is enabled struct dirent + struct dirent64 are actually the same. We require this, and * we want them to be interchangeable to make getdents64() work, hence verify that. */ assert_cc(_FILE_OFFSET_BITS == 64); +#if HAVE_STRUCT_DIRENT64 assert_cc(sizeof(struct dirent) == sizeof(struct dirent64)); assert_cc(offsetof(struct dirent, d_ino) == offsetof(struct dirent64, d_ino)); assert_cc(sizeof_field(struct dirent, d_ino) == sizeof_field(struct dirent64, d_ino)); @@ -46,6 +47,7 @@ assert_cc(offsetof(struct dirent, d_type) == offsetof(struct dirent64, d_type)); assert_cc(sizeof_field(struct dirent, d_type) == sizeof_field(struct dirent64, d_type)); assert_cc(offsetof(struct dirent, d_name) == offsetof(struct dirent64, d_name)); assert_cc(sizeof_field(struct dirent, d_name) == sizeof_field(struct dirent64, d_name)); +#endif #define FOREACH_DIRENT_IN_BUFFER(de, buf, sz) \ for (void *_end = (uint8_t*) ({ (de) = (buf); }) + (sz); \ diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h index c14302ec7..be6428925 100644 --- a/src/basic/hash-funcs.h +++ b/src/basic/hash-funcs.h @@ -102,7 +102,7 @@ extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on * 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 -void devt_hash_func(const dev_t *p, struct siphash *state) _pure_; +void devt_hash_func(const dev_t *p, struct siphash *state); #else #define devt_hash_func uint64_hash_func #endif diff --git a/src/basic/list.h b/src/basic/list.h index ca3003969..c0d5af606 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -133,8 +133,11 @@ } \ } while (false) -#define LIST_JUST_US(name,item) \ - (!(item)->name##_prev && !(item)->name##_next) +#define LIST_JUST_US(name, item) \ + ({ \ + typeof(*(item)) *_item = (item); \ + !(_item)->name##_prev && !(_item)->name##_next; \ + }) /* The type of the iterator 'i' is automatically determined by the type of 'head', and declared in the * loop. Hence, do not declare the same variable in the outer scope. Sometimes, we set 'head' through diff --git a/src/basic/log.c b/src/basic/log.c index 39d08b092..9040d17e8 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -23,6 +23,7 @@ #include "log.h" #include "macro.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "parse-util.h" #include "proc-cmdline.h" #include "process-util.h" @@ -1199,6 +1200,24 @@ LogTarget log_get_target(void) { return log_target; } +void log_settle_target(void) { + + /* If we're using LOG_TARGET_AUTO and opening the log again on every single log call, we'll check if + * stderr is attached to the journal every single log call. However, if we then close all file + * descriptors later, that will stop working because stderr will be closed as well. To avoid that + * problem, this function is used to permanently change the log target depending on whether stderr is + * connected to the journal or not. */ + + LogTarget t = log_get_target(); + + if (t != LOG_TARGET_AUTO) + return; + + t = getpid_cached() == 1 || stderr_is_journal() ? (prohibit_ipc ? LOG_TARGET_KMSG : LOG_TARGET_JOURNAL_OR_KMSG) + : LOG_TARGET_CONSOLE; + log_set_target(t); +} + int log_get_max_level(void) { return log_max_level; } diff --git a/src/basic/log.h b/src/basic/log.h index c51941c14..560686ec1 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -51,6 +51,7 @@ LogTarget log_target_from_string(const char *s) _pure_; void log_set_target(LogTarget target); int log_set_target_from_string(const char *e); LogTarget log_get_target(void) _pure_; +void log_settle_target(void); void log_set_max_level(int level); int log_set_max_level_from_string(const char *e); diff --git a/src/basic/macro.h b/src/basic/macro.h index 237117db1..e2d0bcdbe 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -268,6 +268,10 @@ static inline int __coverity_check_and_return__(int condition) { #define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member) +/* Maximum buffer size needed for formatting an unsigned integer type as hex, including space for '0x' + * prefix and trailing NUL suffix. */ +#define HEXADECIMAL_STR_MAX(type) (2 + sizeof(type) * 2 + 1) + /* Returns the number of chars needed to format variables of the specified type as a decimal string. Adds in * extra space for a negative '-' prefix for signed types. Includes space for the trailing NUL. */ #define DECIMAL_STR_MAX(type) \ @@ -315,20 +319,6 @@ static inline int __coverity_check_and_return__(int condition) { p != (typeof(p)) POINTER_MAX; \ p = *(++_l)) -/* Define C11 thread_local attribute even on older gcc compiler - * version */ -#ifndef thread_local -/* - * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ - * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 - */ -#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) -#define thread_local _Thread_local -#else -#define thread_local __thread -#endif -#endif - #define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ static inline void name(type *p) { \ func(p); \ diff --git a/src/basic/memory-util.c b/src/basic/memory-util.c index 298376211..84b5b2d5c 100644 --- a/src/basic/memory-util.c +++ b/src/basic/memory-util.c @@ -3,6 +3,7 @@ #include #include "memory-util.h" +#include "missing_threads.h" size_t page_size(void) { static thread_local size_t pgsz = 0; diff --git a/src/basic/missing_threads.h b/src/basic/missing_threads.h new file mode 100644 index 000000000..fb3b72249 --- /dev/null +++ b/src/basic/missing_threads.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* If threads.h doesn't exist, then define our own thread_local to match C11's thread_local. */ +#if HAVE_THREADS_H +# include +#elif !(defined(thread_local)) +/* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */ +# if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +# define thread_local _Thread_local +# else +# define thread_local __thread +# endif +#endif diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index dc682688a..3c95179f8 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -118,7 +118,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn r = read_full_virtual_file(path, &fdinfo, NULL); if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ - return -EOPNOTSUPP; + return proc_mounted() > 0 ? -EOPNOTSUPP : -ENOSYS; if (r < 0) return r; @@ -275,7 +275,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { fallback_fdinfo: r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM)) + if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM, -ENOSYS)) goto fallback_fstat; if (r < 0) return r; @@ -493,6 +493,8 @@ int dev_is_devtmpfs(void) { return r; r = fopen_unlocked("/proc/self/mountinfo", "re", &proc_self_mountinfo); + if (r == -ENOENT) + return proc_mounted() > 0 ? -ENOENT : -ENOSYS; if (r < 0) return r; @@ -512,12 +514,12 @@ int dev_is_devtmpfs(void) { if (mid != mount_id) continue; - e = strstr(line, " - "); + e = strstrafter(line, " - "); if (!e) continue; /* accept any name that starts with the currently expected type */ - if (startswith(e + 3, "devtmpfs")) + if (startswith(e, "devtmpfs")) return true; } diff --git a/src/basic/process-util.c b/src/basic/process-util.c index ce66b8c73..35246a95e 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -34,6 +34,7 @@ #include "memory-util.h" #include "missing_sched.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "namespace-util.h" #include "path-util.h" #include "process-util.h" @@ -1305,6 +1306,7 @@ int safe_fork_full( /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */ log_close(); log_set_open_when_needed(true); + log_settle_target(); } if (name) { diff --git a/src/basic/random-util.c b/src/basic/random-util.c index d8734cc7d..200a91419 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -24,6 +24,7 @@ #include "io-util.h" #include "missing_random.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "parse-util.h" #include "random-util.h" #include "sha256.h" diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index c16c8f710..1e1d5be3d 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -43,3 +43,21 @@ unsigned ratelimit_num_dropped(RateLimit *r) { return r->num > r->burst ? r->num - r->burst : 0; } + +usec_t ratelimit_end(const RateLimit *rl) { + assert(rl); + + if (rl->begin == 0) + return 0; + + return usec_add(rl->begin, rl->interval); +} + +usec_t ratelimit_left(const RateLimit *rl) { + assert(rl); + + if (rl->begin == 0) + return 0; + + return usec_sub_unsigned(ratelimit_end(rl), now(CLOCK_MONOTONIC)); +} diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 223618985..bb7160a89 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -23,3 +23,6 @@ static inline bool ratelimit_configured(RateLimit *rl) { bool ratelimit_below(RateLimit *r); unsigned ratelimit_num_dropped(RateLimit *r); + +usec_t ratelimit_end(const RateLimit *rl); +usec_t ratelimit_left(const RateLimit *rl); diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index b61c18b2d..fdbe7f43a 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -5,6 +5,7 @@ #include "errno-util.h" #include "macro.h" +#include "missing_threads.h" #include "parse-util.h" #include "signal-util.h" #include "stdio-util.h" diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index f39be19a5..cefbbcd9a 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1307,7 +1307,7 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { return n; } -int socket_get_family(int fd, int *ret) { +int socket_get_family(int fd) { int af; socklen_t sl = sizeof(af); @@ -1321,12 +1321,11 @@ int socket_get_family(int fd, int *ret) { } int socket_set_recvpktinfo(int fd, int af, bool b) { - int r; if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; + af = socket_get_family(fd); + if (af < 0) + return af; } switch (af) { @@ -1350,12 +1349,11 @@ int socket_set_recvpktinfo(int fd, int af, bool b) { int socket_set_unicast_if(int fd, int af, int ifi) { be32_t ifindex_be = htobe32(ifi); - int r; if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; + af = socket_get_family(fd); + if (af < 0) + return af; } switch (af) { @@ -1372,12 +1370,10 @@ int socket_set_unicast_if(int fd, int af, int ifi) { } int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) { - int r; - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; + af = socket_get_family(fd); + if (af < 0) + return af; } switch (af) { @@ -1397,9 +1393,9 @@ int socket_get_mtu(int fd, int af, size_t *ret) { int mtu, r; if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; + af = socket_get_family(fd); + if (af < 0) + return af; } switch (af) { diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 2e36e1a56..97a6282d9 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -304,7 +304,7 @@ struct timespec_large { ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); -int socket_get_family(int fd, int *ret); +int socket_get_family(int fd); int socket_set_recvpktinfo(int fd, int af, bool b); int socket_set_unicast_if(int fd, int af, int ifi); diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 51adaca9d..468840d2a 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -189,10 +189,10 @@ int files_same(const char *filea, const char *fileb, int flags) { assert(fileb); if (fstatat(AT_FDCWD, filea, &a, flags) < 0) - return -errno; + return log_debug_errno(errno, "Cannot stat %s: %m", filea); if (fstatat(AT_FDCWD, fileb, &b, flags) < 0) - return -errno; + return log_debug_errno(errno, "Cannot stat %s: %m", fileb); return stat_inode_same(&a, &b); } diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 46681ced9..913a96f54 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -29,6 +29,18 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) { return strstr(haystack, needle); } +static inline char *strstrafter(const char *haystack, const char *needle) { + char *p; + + /* Returns NULL if not found, or pointer to first character after needle if found */ + + p = strstr_ptr(haystack, needle); + if (!p) + return NULL; + + return p + strlen(needle); +} + static inline const char* strnull(const char *s) { return s ?: "(null)"; } diff --git a/src/basic/syscall-list.txt b/src/basic/syscall-list.txt index fbc5566a6..616bda711 100644 --- a/src/basic/syscall-list.txt +++ b/src/basic/syscall-list.txt @@ -427,6 +427,7 @@ renameat2 request_key restart_syscall riscv_flush_icache +riscv_hwprobe rmdir rseq rt_sigaction diff --git a/src/basic/syscalls-alpha.txt b/src/basic/syscalls-alpha.txt index 38988407f..641e1a43a 100644 --- a/src/basic/syscalls-alpha.txt +++ b/src/basic/syscalls-alpha.txt @@ -427,6 +427,7 @@ renameat2 510 request_key 440 restart_syscall 412 riscv_flush_icache +riscv_hwprobe rmdir 137 rseq 527 rt_sigaction 352 diff --git a/src/basic/syscalls-arc.txt b/src/basic/syscalls-arc.txt index 801f551c2..0f8250453 100644 --- a/src/basic/syscalls-arc.txt +++ b/src/basic/syscalls-arc.txt @@ -427,6 +427,7 @@ renameat2 276 request_key 218 restart_syscall 128 riscv_flush_icache +riscv_hwprobe rmdir rseq 293 rt_sigaction 134 diff --git a/src/basic/syscalls-arm.txt b/src/basic/syscalls-arm.txt index 94bbcbf70..013b89988 100644 --- a/src/basic/syscalls-arm.txt +++ b/src/basic/syscalls-arm.txt @@ -427,6 +427,7 @@ renameat2 382 request_key 310 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 398 rt_sigaction 174 diff --git a/src/basic/syscalls-arm64.txt b/src/basic/syscalls-arm64.txt index 207c43937..717c873d8 100644 --- a/src/basic/syscalls-arm64.txt +++ b/src/basic/syscalls-arm64.txt @@ -427,6 +427,7 @@ renameat2 276 request_key 218 restart_syscall 128 riscv_flush_icache +riscv_hwprobe rmdir rseq 293 rt_sigaction 134 diff --git a/src/basic/syscalls-i386.txt b/src/basic/syscalls-i386.txt index 4c0c99368..96170784d 100644 --- a/src/basic/syscalls-i386.txt +++ b/src/basic/syscalls-i386.txt @@ -427,6 +427,7 @@ renameat2 353 request_key 287 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 386 rt_sigaction 174 diff --git a/src/basic/syscalls-ia64.txt b/src/basic/syscalls-ia64.txt index 9346b2e0d..4b6481e1d 100644 --- a/src/basic/syscalls-ia64.txt +++ b/src/basic/syscalls-ia64.txt @@ -427,6 +427,7 @@ renameat2 1338 request_key 1272 restart_syscall 1246 riscv_flush_icache +riscv_hwprobe rmdir 1056 rseq 1357 rt_sigaction 1177 diff --git a/src/basic/syscalls-loongarch64.txt b/src/basic/syscalls-loongarch64.txt index a6a0bca93..9222352c2 100644 --- a/src/basic/syscalls-loongarch64.txt +++ b/src/basic/syscalls-loongarch64.txt @@ -427,6 +427,7 @@ renameat2 276 request_key 218 restart_syscall 128 riscv_flush_icache +riscv_hwprobe rmdir rseq 293 rt_sigaction 134 diff --git a/src/basic/syscalls-m68k.txt b/src/basic/syscalls-m68k.txt index f5a95685f..3427196dc 100644 --- a/src/basic/syscalls-m68k.txt +++ b/src/basic/syscalls-m68k.txt @@ -427,6 +427,7 @@ renameat2 351 request_key 280 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 384 rt_sigaction 174 diff --git a/src/basic/syscalls-mips64.txt b/src/basic/syscalls-mips64.txt index 7d0b9976b..aded3d24d 100644 --- a/src/basic/syscalls-mips64.txt +++ b/src/basic/syscalls-mips64.txt @@ -427,6 +427,7 @@ renameat2 5311 request_key 5240 restart_syscall 5213 riscv_flush_icache +riscv_hwprobe rmdir 5082 rseq 5327 rt_sigaction 5013 diff --git a/src/basic/syscalls-mips64n32.txt b/src/basic/syscalls-mips64n32.txt index 2e15c6612..76e81e65b 100644 --- a/src/basic/syscalls-mips64n32.txt +++ b/src/basic/syscalls-mips64n32.txt @@ -427,6 +427,7 @@ renameat2 6315 request_key 6244 restart_syscall 6214 riscv_flush_icache +riscv_hwprobe rmdir 6082 rseq 6331 rt_sigaction 6013 diff --git a/src/basic/syscalls-mipso32.txt b/src/basic/syscalls-mipso32.txt index a8d95e3e3..02fa281b5 100644 --- a/src/basic/syscalls-mipso32.txt +++ b/src/basic/syscalls-mipso32.txt @@ -427,6 +427,7 @@ renameat2 4351 request_key 4281 restart_syscall 4253 riscv_flush_icache +riscv_hwprobe rmdir 4040 rseq 4367 rt_sigaction 4194 diff --git a/src/basic/syscalls-parisc.txt b/src/basic/syscalls-parisc.txt index 905729f81..e409d69de 100644 --- a/src/basic/syscalls-parisc.txt +++ b/src/basic/syscalls-parisc.txt @@ -427,6 +427,7 @@ renameat2 337 request_key 265 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 354 rt_sigaction 174 diff --git a/src/basic/syscalls-powerpc.txt b/src/basic/syscalls-powerpc.txt index ad68616e2..7e7024834 100644 --- a/src/basic/syscalls-powerpc.txt +++ b/src/basic/syscalls-powerpc.txt @@ -427,6 +427,7 @@ renameat2 357 request_key 270 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 387 rt_sigaction 173 diff --git a/src/basic/syscalls-powerpc64.txt b/src/basic/syscalls-powerpc64.txt index 9e8dc6dd8..e9c37cd1d 100644 --- a/src/basic/syscalls-powerpc64.txt +++ b/src/basic/syscalls-powerpc64.txt @@ -427,6 +427,7 @@ renameat2 357 request_key 270 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 387 rt_sigaction 173 diff --git a/src/basic/syscalls-riscv32.txt b/src/basic/syscalls-riscv32.txt index 50f4de65b..6ef882f3d 100644 --- a/src/basic/syscalls-riscv32.txt +++ b/src/basic/syscalls-riscv32.txt @@ -427,6 +427,7 @@ renameat2 276 request_key 218 restart_syscall 128 riscv_flush_icache 259 +riscv_hwprobe 258 rmdir rseq 293 rt_sigaction 134 diff --git a/src/basic/syscalls-riscv64.txt b/src/basic/syscalls-riscv64.txt index afa33b2bc..700ff225b 100644 --- a/src/basic/syscalls-riscv64.txt +++ b/src/basic/syscalls-riscv64.txt @@ -427,6 +427,7 @@ renameat2 276 request_key 218 restart_syscall 128 riscv_flush_icache 259 +riscv_hwprobe 258 rmdir rseq 293 rt_sigaction 134 diff --git a/src/basic/syscalls-s390.txt b/src/basic/syscalls-s390.txt index bbc824c00..caa89112b 100644 --- a/src/basic/syscalls-s390.txt +++ b/src/basic/syscalls-s390.txt @@ -204,7 +204,7 @@ madvise 219 mbind 268 membarrier 356 memfd_create 350 -memfd_secret +memfd_secret 447 memory_ordering migrate_pages 287 mincore 218 @@ -427,6 +427,7 @@ renameat2 347 request_key 279 restart_syscall 7 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 383 rt_sigaction 174 diff --git a/src/basic/syscalls-s390x.txt b/src/basic/syscalls-s390x.txt index bc385eaba..a18a9a565 100644 --- a/src/basic/syscalls-s390x.txt +++ b/src/basic/syscalls-s390x.txt @@ -204,7 +204,7 @@ madvise 219 mbind 268 membarrier 356 memfd_create 350 -memfd_secret +memfd_secret 447 memory_ordering migrate_pages 287 mincore 218 @@ -427,6 +427,7 @@ renameat2 347 request_key 279 restart_syscall 7 riscv_flush_icache +riscv_hwprobe rmdir 40 rseq 383 rt_sigaction 174 diff --git a/src/basic/syscalls-sparc.txt b/src/basic/syscalls-sparc.txt index 6c39ad86f..991f7da20 100644 --- a/src/basic/syscalls-sparc.txt +++ b/src/basic/syscalls-sparc.txt @@ -427,6 +427,7 @@ renameat2 345 request_key 282 restart_syscall 0 riscv_flush_icache +riscv_hwprobe rmdir 137 rseq 365 rt_sigaction 102 diff --git a/src/basic/syscalls-x86_64.txt b/src/basic/syscalls-x86_64.txt index 2942c2e48..40df5e1ba 100644 --- a/src/basic/syscalls-x86_64.txt +++ b/src/basic/syscalls-x86_64.txt @@ -427,6 +427,7 @@ renameat2 316 request_key 249 restart_syscall 219 riscv_flush_icache +riscv_hwprobe rmdir 84 rseq 334 rt_sigaction 13 diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 71b2f6735..f5e10bba1 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -17,6 +17,7 @@ #include "io-util.h" #include "log.h" #include "macro.h" +#include "missing_threads.h" #include "missing_timerfd.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/basic/user-util.c b/src/basic/user-util.c index e2857b310..15a2b145c 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -21,7 +21,6 @@ #include "macro.h" #include "parse-util.h" #include "path-util.h" -#include "path-util.h" #include "random-util.h" #include "string-util.h" #include "strv.h" diff --git a/src/basic/virt.c b/src/basic/virt.c index 30a2b4e66..2c9ab3d8e 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -16,6 +16,7 @@ #include "fd-util.h" #include "fileio.h" #include "macro.h" +#include "missing_threads.h" #include "process-util.h" #include "stat-util.h" #include "string-table.h" @@ -263,6 +264,7 @@ static Virtualization detect_vm_dmi(void) { * so we fallback to using the product name which is less restricted * to distinguish metal systems from virtualized instances */ _cleanup_free_ char *s = NULL; + const char *e; r = read_full_virtual_file("/sys/class/dmi/id/product_name", &s, NULL); /* In EC2, virtualized is much more common than metal, so if for some reason @@ -272,8 +274,9 @@ static Virtualization detect_vm_dmi(void) { " assuming virtualized: %m"); return VIRTUALIZATION_AMAZON; } - if (endswith(truncate_nl(s), ".metal")) { - log_debug("DMI product name ends with '.metal', assuming no virtualization"); + e = strstrafter(truncate_nl(s), ".metal"); + if (e && IN_SET(*e, 0, '-')) { + log_debug("DMI product name has '.metal', assuming no virtualization"); return VIRTUALIZATION_NONE; } else return VIRTUALIZATION_AMAZON; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 997214193..61eed6160 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -368,7 +368,7 @@ static int settle_make_entry_directory(void) { bool layout_type1 = use_boot_loader_spec_type1(); if (arg_make_entry_directory < 0) { /* Automatic mode */ if (layout_type1) { - if (arg_entry_token == ARG_ENTRY_TOKEN_MACHINE_ID) { + if (arg_entry_token_type == ARG_ENTRY_TOKEN_MACHINE_ID) { r = path_is_temporary_fs("/etc/machine-id"); if (r < 0) return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m"); @@ -1126,7 +1126,8 @@ static int install_variables( uint64_t psize, sd_id128_t uuid, const char *path, - bool first) { + bool first, + bool graceful) { uint16_t slot; int r; @@ -1149,18 +1150,30 @@ static int install_variables( return log_error_errno(r, "Cannot access \"%s/%s\": %m", esp_path, path); r = find_slot(uuid, path, &slot); - if (r < 0) - return log_error_errno(r, - r == -ENOENT ? - "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" : - "Failed to determine current boot order: %m"); + if (r < 0) { + int level = graceful ? arg_quiet ? LOG_DEBUG : LOG_INFO : LOG_ERR; + const char *skip = graceful ? ", skipping" : ""; + + log_full_errno(level, r, + r == -ENOENT ? + "Failed to access EFI variables%s. Is the \"efivarfs\" filesystem mounted?" : + "Failed to determine current boot order%s: %m", skip); + + return graceful ? 0 : r; + } if (first || r == 0) { 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"); + if (r < 0) { + int level = graceful ? arg_quiet ? LOG_DEBUG : LOG_INFO : LOG_ERR; + const char *skip = graceful ? ", skipping" : ""; + + log_full_errno(level, r, "Failed to create EFI Boot variable entry%s: %m", skip); + + return graceful ? 0 : r; + } log_info("Created EFI boot entry \"%s\".", pick_efi_boot_option_description()); } @@ -2228,7 +2241,7 @@ static int verb_install(int argc, char *argv[], void *userdata) { } char *path = strjoina("/EFI/systemd/systemd-boot", arch, ".efi"); - return install_variables(arg_esp_path, part, pstart, psize, uuid, path, install); + return install_variables(arg_esp_path, part, pstart, psize, uuid, path, install, graceful); } static int verb_remove(int argc, char *argv[], void *userdata) { diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index 823ef0de1..0196314c6 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -19,7 +19,7 @@ elif efi_arch == 'x86_64' and '-m32' in get_option('efi-cflags') efi_arch = 'x86' endif efi_arch = { - # host_cc_arch: [efi_arch (see Table 3-2 in UEFI spec), gnu_efi_inc_arch] + # host_cc_arch: [efi_arch (see Table 3-2 in UEFI spec), obsolete gnu_efi_inc_arch] 'x86': ['ia32', 'ia32'], 'x86_64': ['x64', 'x86_64'], 'arm': ['arm', 'arm'], @@ -28,14 +28,17 @@ efi_arch = { }.get(efi_arch, []) efi_incdir = get_option('efi-includedir') -if efi_arch.length() > 0 and not cc.has_header( - '@0@/@1@/efibind.h'.format(efi_incdir, efi_arch[1]), - args: get_option('efi-cflags')) +found = false +foreach efi_arch_candidate : efi_arch + efi_archdir = efi_incdir / efi_arch_candidate + if cc.has_header(efi_archdir / 'efibind.h', + args: get_option('efi-cflags')) + found = true + break + endif +endforeach - efi_arch = [] -endif - -if efi_arch.length() == 0 +if not found if get_option('gnu-efi') == 'true' error('gnu-efi support requested, but headers not found or efi arch is unknown') endif @@ -45,7 +48,8 @@ endif if not cc.has_header_symbol('efi.h', 'EFI_IMAGE_MACHINE_X64', args: ['-nostdlib', '-ffreestanding', '-fshort-wchar'] + get_option('efi-cflags'), - include_directories: include_directories(efi_incdir, efi_incdir / efi_arch[1])) + include_directories: include_directories(efi_incdir, + efi_archdir)) if get_option('gnu-efi') == 'true' error('gnu-efi support requested, but found headers are too old (3.0.5+ required)') @@ -185,7 +189,7 @@ efi_cflags = [ '-I', meson.current_source_dir(), '-include', efi_config_h, '-include', version_h, - '-isystem', efi_incdir / efi_arch[1], + '-I', efi_archdir, '-isystem', efi_incdir, '-std=gnu11', '-Wall', @@ -342,7 +346,7 @@ summary({ 'EFI LD' : efi_ld, 'EFI lds' : efi_lds, 'EFI crt0' : efi_crt0, - 'EFI include directory' : efi_incdir}, + 'EFI include directory' : efi_archdir}, section : 'Extensible Firmware Interface') if efi_conf.get('SBAT_DISTRO', '') != '' diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index ac614415c..9f8439480 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -46,7 +46,7 @@ static inline void freep(void *p) { _malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_ static inline void *xmalloc(size_t size) { void *p; - assert_se(BS->AllocatePool(EfiBootServicesData, size, &p) == EFI_SUCCESS); + assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS); return p; } diff --git a/src/boot/pcrphase.c b/src/boot/pcrphase.c index e5d33ff1a..2808ee8c9 100644 --- a/src/boot/pcrphase.c +++ b/src/boot/pcrphase.c @@ -23,7 +23,7 @@ static int help(int argc, char *argv[], void *userdata) { _cleanup_free_ char *link = NULL; int r; - r = terminal_urlify_man("systemd-pcrphase", "1", &link); + r = terminal_urlify_man("systemd-pcrphase", "8", &link); if (r < 0) return log_oom(); diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index cc2d0e345..9e46cc2e9 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -37,7 +37,7 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; static bool arg_legend = true; -static bool arg_full = false; +static int arg_full = -1; static const char *arg_address = NULL; static bool arg_unique = false; static bool arg_acquired = false; @@ -75,6 +75,8 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) { if (r < 0) return log_error_errno(r, "Failed to allocate bus: %m"); + (void) sd_bus_set_description(bus, "busctl"); + if (set_monitor) { r = sd_bus_set_monitor(bus, true); if (r < 0) @@ -202,7 +204,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (!table) return log_oom(); - if (arg_full) + if (arg_full > 0) table_set_width(table, 0); r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100); @@ -356,9 +358,6 @@ static int list_bus_names(int argc, char **argv, void *userdata) { } static void print_subtree(const char *prefix, const char *path, char **l) { - const char *vertical, *space; - char **n; - /* We assume the list is sorted. Let's first skip over the * entry we are looking at. */ for (;;) { @@ -371,11 +370,13 @@ static void print_subtree(const char *prefix, const char *path, char **l) { l++; } - vertical = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL)); - space = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_SPACE)); + const char + *vertical = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL)), + *space = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_SPACE)); for (;;) { bool has_more = false; + char **n; if (!*l || !path_startswith(*l, path)) break; @@ -960,8 +961,8 @@ static int introspect(int argc, char **argv, void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(member_set_freep) Set *members = NULL; - unsigned name_width, type_width, signature_width, result_width, j, k = 0; - Member *m, **sorted = NULL; + unsigned name_width, type_width, signature_width, result_width; + Member *m; const char *xml; int r; @@ -1095,7 +1096,8 @@ static int introspect(int argc, char **argv, void *userdata) { signature_width = strlen("SIGNATURE"); result_width = strlen("RESULT/VALUE"); - sorted = newa(Member*, set_size(members)); + Member **sorted = newa(Member*, set_size(members)); + size_t k = 0; SET_FOREACH(m, members) { if (argv[3] && !streq(argv[3], m->interface)) @@ -1117,7 +1119,7 @@ static int introspect(int argc, char **argv, void *userdata) { sorted[k++] = m; } - if (result_width > 40) + if (result_width > 40 && arg_full <= 0) result_width = 40; typesafe_qsort(sorted, k, member_compare_funcp); @@ -1132,7 +1134,7 @@ static int introspect(int argc, char **argv, void *userdata) { (int) result_width, "RESULT/VALUE", "FLAGS"); - for (j = 0; j < k; j++) { + for (size_t j = 0; j < k; j++) { _cleanup_free_ char *ellipsized = NULL; const char *rv; bool is_interface; @@ -2304,6 +2306,7 @@ static int help(void) { " --verbose Show result values in long format\n" " --json=MODE Output as JSON\n" " -j Same as --json=pretty on tty, --json=short otherwise\n" + " --xml-interface Dump the XML description in introspect command\n" " --expect-reply=BOOL Expect a method call reply\n" " --auto-start=BOOL Auto-start destination service\n" " --allow-interactive-authorization=BOOL\n" @@ -2547,6 +2550,9 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } + if (arg_full < 0) + arg_full = terminal_is_dumb(); + return 1; } diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 6af95204e..7107d2286 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -95,6 +95,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 1); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "-hkalM:u::", options, NULL)) >= 0) switch (c) { diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 119bb95d3..6fa483e70 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1357,17 +1357,47 @@ static int dump_impl( assert(message); - /* Anyone can call this method */ - + /* 'status' access is the bare minimum always needed for this, as the policy might straight out + * forbid a client from querying any information from systemd, regardless of any rate limiting. */ r = mac_selinux_access_check(message, "status", error); if (r < 0) return r; + /* Rate limit reached? Check if the caller is privileged/allowed by policy to bypass this. We + * check the rate limit first to avoid the expensive roundtrip to polkit when not needed. */ + if (!ratelimit_below(&m->dump_ratelimit)) { + /* We need a way for SELinux to constrain the operation when the rate limit is active, even + * if polkit would allow it, but we cannot easily add new named permissions, so we need to + * use an existing one. Reload/reexec are also slow but non-destructive/modifying + * operations, and can cause PID1 to stall. So it seems similar enough in terms of security + * considerations and impact, and thus use the same access check for dumps which, given the + * large amount of data to fetch, can stall PID1 for quite some time. */ + r = mac_selinux_access_check(message, "reload", error); + if (r < 0) + goto ratelimited; + + r = bus_verify_bypass_dump_ratelimit_async(m, message, error); + if (r < 0) + goto ratelimited; + if (r == 0) + /* No authorization for now, but the async polkit stuff will call us again when it + * has it */ + return 1; + } + r = manager_get_dump_string(m, patterns, &dump); if (r < 0) return r; return reply(message, dump); + +ratelimited: + log_warning("Dump request rejected due to rate limit on unprivileged callers, blocked for %s.", + FORMAT_TIMESPAN(ratelimit_left(&m->dump_ratelimit), USEC_PER_SEC)); + return sd_bus_error_setf(error, + SD_BUS_ERROR_LIMITS_EXCEEDED, + "Dump request rejected due to rate limit on unprivileged callers, blocked for %s.", + FORMAT_TIMESPAN(ratelimit_left(&m->dump_ratelimit), USEC_PER_SEC)); } static int reply_dump(sd_bus_message *message, char *dump) { diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 6e4bc0bd1..0fb4f4384 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -188,6 +188,29 @@ int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_b return bus_service_method_mount(message, userdata, error, true); } +#if __SIZEOF_SIZE_T__ == 8 +static int property_get_size_as_uint32( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + size_t *value = ASSERT_PTR(userdata); + uint32_t sz = *value >= UINT32_MAX ? UINT32_MAX : (uint32_t) *value; + + /* Returns a size_t as a D-Bus "u" type, i.e. as 32bit value, even if size_t is 64bit. We'll saturate if it doesn't fit. */ + + return sd_bus_message_append_basic(reply, 'u', &sz); +} +#elif __SIZEOF_SIZE_T__ == 4 +#define property_get_size_as_uint32 ((sd_bus_property_get_t) NULL) +#else +#error "Unexpected size of size_t" +#endif + const sd_bus_vtable bus_service_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST), @@ -216,7 +239,7 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0), + SD_BUS_PROPERTY("NFileDescriptorStore", "u", property_get_size_as_uint32, offsetof(Service, n_fd_store), 0), SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StatusErrno", "i", bus_property_get_int, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 0702373ab..39b42df90 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -2397,7 +2397,7 @@ int bus_unit_set_properties( r = sd_bus_message_enter_container(message, 'a', "(sv)"); if (r < 0) - return r; + goto error; for (;;) { const char *name; @@ -2405,7 +2405,7 @@ int bus_unit_set_properties( r = sd_bus_message_enter_container(message, 'r', "sv"); if (r < 0) - return r; + goto error; if (r == 0) { if (for_real || UNIT_WRITE_FLAGS_NOOP(flags)) break; @@ -2413,7 +2413,7 @@ int bus_unit_set_properties( /* Reached EOF. Let's try again, and this time for realz... */ r = sd_bus_message_rewind(message, false); if (r < 0) - return r; + goto error; for_real = true; continue; @@ -2421,11 +2421,11 @@ int bus_unit_set_properties( r = sd_bus_message_read(message, "s", &name); if (r < 0) - return r; + goto error; r = sd_bus_message_enter_container(message, 'v', NULL); if (r < 0) - return r; + goto error; /* If not for real, then mask out the two target flags */ f = for_real ? flags : (flags & ~(UNIT_RUNTIME|UNIT_PERSISTENT)); @@ -2439,7 +2439,7 @@ int bus_unit_set_properties( if (r == 0) r = bus_unit_set_live_property(u, name, message, f, error); if (r < 0) - return r; + goto error; if (r == 0) return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, @@ -2447,23 +2447,32 @@ int bus_unit_set_properties( r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto error; r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto error; n += for_real; } r = sd_bus_message_exit_container(message); if (r < 0) - return r; + goto error; if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) UNIT_VTABLE(u)->bus_commit_properties(u); return n; + + error: + /* Pretty much any of the calls above can fail if the message is not formed properly + * or if it has unexpected contents. Fill in a more informative error message here. */ + if (sd_bus_error_is_set(error)) + return r; + return sd_bus_error_set_errnof(error, r, + r == -ENXIO ? "Failed to set unit properties: Unexpected message contents" + : "Failed to set unit properties: %m"); } int bus_unit_validate_load_state(Unit *u, sd_bus_error *error) { diff --git a/src/core/dbus.c b/src/core/dbus.c index 141c3ffe1..3cbe9c5cf 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -1177,6 +1177,9 @@ int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_erro int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", NULL, false, UID_INVALID, &m->polkit_registry, error); } +int bus_verify_bypass_dump_ratelimit_async(Manager *m, sd_bus_message *call, sd_bus_error *error) { + return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.bypass-dump-ratelimit", NULL, false, UID_INVALID, &m->polkit_registry, error); +} uint64_t manager_bus_n_queued_write(Manager *m) { uint64_t c = 0; diff --git a/src/core/dbus.h b/src/core/dbus.h index 369d9f56a..50e7bb400 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -27,6 +27,7 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error); +int bus_verify_bypass_dump_ratelimit_async(Manager *m, sd_bus_message *call, sd_bus_error *error); int bus_forward_agent_released(Manager *m, const char *path); diff --git a/src/core/device.c b/src/core/device.c index 6e07f2745..4881876e5 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -6,7 +6,7 @@ #include "sd-messages.h" #include "alloc-util.h" -#include "bus-error.h" +#include "bus-common-errors.h" #include "dbus-device.h" #include "dbus-unit.h" #include "device-private.h" @@ -612,7 +612,8 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) { r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL); if (r < 0) - log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r)); + log_unit_full_errno(u, sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to enqueue %s job, ignoring: %s", property, bus_error_message(&error, r)); } return strv_free_and_replace(d->wants_property, added); diff --git a/src/core/execute.c b/src/core/execute.c index 13222ddea..22d952fd0 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -4190,6 +4190,7 @@ static int exec_child( log_forget_fds(); log_set_open_when_needed(true); + log_settle_target(); /* In case anything used libc syslog(), close this here, too */ closelog(); diff --git a/src/core/job.c b/src/core/job.c index 032554a0a..826ef6809 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1001,7 +1001,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr } /* A special check to make sure we take down anything RequisiteOf= if we aren't active. This is when - * the verify-active job merges with a satisfying job type, and then loses it's invalidation effect, + * the verify-active job merges with a satisfying job type, and then loses its invalidation effect, * as the result there is JOB_DONE for the start job we merged into, while we should be failing the * depending job if the said unit isn't in fact active. Oneshots are an example of this, where going * directly from activating to inactive is success. @@ -1051,6 +1051,12 @@ finish: job_add_to_gc_queue(other->job); } + /* Ensure that when an upheld/unneeded/bound unit activation job fails we requeue it, if it still + * necessary. If there are no state changes in the triggerer, it would not be retried otherwise. */ + unit_submit_to_start_when_upheld_queue(u); + unit_submit_to_stop_when_bound_queue(u); + unit_submit_to_stop_when_unneeded_queue(u); + manager_check_finished(u->manager); return 0; diff --git a/src/core/job.h b/src/core/job.h index 30a7903aa..807c2583b 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -222,7 +222,7 @@ char *job_dbus_path(Job *j); void job_shutdown_magic(Job *j); -int job_get_timeout(Job *j, usec_t *timeout) _pure_; +int job_get_timeout(Job *j, usec_t *timeout); bool job_may_gc(Job *j); void job_add_to_gc_queue(Job *j); diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 966631d44..15337d00a 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -10,6 +10,7 @@ #include "macro.h" #include "recurse-dir.h" #include "string-util.h" +#include "strv.h" #include "virt.h" #if HAVE_KMOD @@ -56,10 +57,7 @@ static int has_virtio_rng_recurse_dir_cb( return RECURSE_DIR_LEAVE_DIRECTORY; } - if (startswith(alias, "pci:v00001AF4d00001005")) - return 1; - - if (startswith(alias, "pci:v00001AF4d00001044")) + if (STARTSWITH_SET(alias, "pci:v00001AF4d00001005", "pci:v00001AF4d00001044")) return 1; return RECURSE_DIR_LEAVE_DIRECTORY; @@ -68,6 +66,10 @@ static int has_virtio_rng_recurse_dir_cb( static bool has_virtio_rng(void) { int r; + /* Directory traversal might be slow, hence let's do a cheap check first if it's even worth it */ + if (detect_vm() == VIRTUALIZATION_NONE) + return false; + r = recurse_dir_at( AT_FDCWD, "/sys/devices/pci0000:00", diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1a5895346..987f98a59 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -798,7 +798,7 @@ int config_parse_exec_coredump_filter( } c->coredump_filter |= f; - c->oom_score_adjust_set = true; + c->coredump_filter_set = true; return 0; } @@ -3932,12 +3932,12 @@ int config_parse_delegate( return 0; } - /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it - * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the - * mask to delegate. */ + /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or + * turn it off for all. Or it takes a list of controller names, in which case we add the specified + * controllers to the mask to delegate. Delegate= enables delegation without any controllers. */ if (isempty(rvalue)) { - /* An empty string resets controllers and set Delegate=yes. */ + /* An empty string resets controllers and sets Delegate=yes. */ c->delegate = true; c->delegate_controllers = 0; return 0; diff --git a/src/core/main.c b/src/core/main.c index 2b746ce8b..de6913c91 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1013,7 +1013,7 @@ static int parse_argv(int argc, char *argv[]) { r = safe_atoi(optarg, &fd); if (r < 0) - log_error_errno(r, "Failed to parse deserialize option \"%s\": %m", optarg); + return log_error_errno(r, "Failed to parse deserialize option \"%s\": %m", optarg); if (fd < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid deserialize fd: %d", @@ -1471,45 +1471,44 @@ static int become_shutdown( const char *shutdown_verb, int retval) { - char log_level[DECIMAL_STR_MAX(int) + 1], - exit_code[DECIMAL_STR_MAX(uint8_t) + 1], - timeout[DECIMAL_STR_MAX(usec_t) + 1]; + char log_level[STRLEN("--log-level=") + DECIMAL_STR_MAX(int)], + exit_code[STRLEN("--exit-code=") + DECIMAL_STR_MAX(uint8_t)], + timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")]; - const char* command_line[13] = { + const char* command_line[14] = { SYSTEMD_SHUTDOWN_BINARY_PATH, shutdown_verb, - "--timeout", timeout, - "--log-level", log_level, - "--log-target", + timeout, + log_level, }; _cleanup_strv_free_ char **env_block = NULL; usec_t watchdog_timer = 0; - size_t pos = 7; + size_t pos = 4; int r; assert(shutdown_verb); assert(!command_line[pos]); env_block = strv_copy(environ); - xsprintf(log_level, "%d", log_get_max_level()); - xsprintf(timeout, "%" PRI_USEC "us", arg_default_timeout_stop_usec); + xsprintf(log_level, "--log-level=%d", log_get_max_level()); + xsprintf(timeout, "--timeout=%" PRI_USEC "us", arg_default_timeout_stop_usec); switch (log_get_target()) { case LOG_TARGET_KMSG: case LOG_TARGET_JOURNAL_OR_KMSG: case LOG_TARGET_SYSLOG_OR_KMSG: - command_line[pos++] = "kmsg"; + command_line[pos++] = "--log-target=kmsg"; break; case LOG_TARGET_NULL: - command_line[pos++] = "null"; + command_line[pos++] = "--log-target=null"; break; case LOG_TARGET_CONSOLE: default: - command_line[pos++] = "console"; + command_line[pos++] = "--log-target=console"; break; }; @@ -1523,9 +1522,8 @@ static int become_shutdown( command_line[pos++] = "--log-time"; if (streq(shutdown_verb, "exit")) { - command_line[pos++] = "--exit-code"; + xsprintf(exit_code, "--exit-code=%d", retval); command_line[pos++] = exit_code; - xsprintf(exit_code, "%d", retval); } assert(pos < ELEMENTSOF(command_line)); @@ -1802,11 +1800,11 @@ static int do_reexecute( log_error_errno(r, "Failed to switch root, trying to continue: %m"); } - args_size = argc + 6; + args_size = argc + 5; args = newa(const char*, args_size); if (!switch_root_init) { - char sfd[DECIMAL_STR_MAX(int)]; + char sfd[STRLEN("--deserialize=") + DECIMAL_STR_MAX(int)]; /* First try to spawn ourselves with the right path, and with full serialization. We do this * only if the user didn't specify an explicit init to spawn. */ @@ -1814,15 +1812,15 @@ static int do_reexecute( assert(arg_serialization); assert(fds); - xsprintf(sfd, "%i", fileno(arg_serialization)); + xsprintf(sfd, "--deserialize=%i", fileno(arg_serialization)); i = 1; /* Leave args[0] empty for now. */ filter_args(args, &i, argv, argc); if (switch_root_dir) args[i++] = "--switched-root"; + args[i++] = arg_system ? "--system" : "--user"; - args[i++] = "--deserialize"; args[i++] = sfd; args[i++] = NULL; @@ -2619,16 +2617,24 @@ static int collect_fds(FDSet **ret_fds, const char **ret_error_message) { assert(ret_fds); assert(ret_error_message); - r = fdset_new_fill(ret_fds); + /* Pick up all fds passed to us. We apply a filter here: we only take the fds that have O_CLOEXEC + * off. All fds passed via execve() to us must have O_CLOEXEC off, and our own code and dependencies + * should be clean enough to set O_CLOEXEC universally. Thus checking the bit should be a safe + * mechanism to distinguish passed in fds from our own. + * + * Why bother? Some subsystems we initialize early, specifically selinux might keep fds open in our + * process behind our back. We should not take possession of that (and then accidentally close + * it). SELinux thankfully sets O_CLOEXEC on its fds, so this test should work. */ + r = fdset_new_fill(/* filter_cloexec= */ 0, ret_fds); if (r < 0) { *ret_error_message = "Failed to allocate fd set"; return log_emergency_errno(r, "Failed to allocate fd set: %m"); } - fdset_cloexec(*ret_fds, true); + (void) fdset_cloexec(*ret_fds, true); - if (arg_serialization) - assert_se(fdset_remove(*ret_fds, fileno(arg_serialization)) >= 0); + /* The serialization fd should have O_CLOEXEC turned on already, let's verify that we didn't pick it up here */ + assert_se(!arg_serialization || !fdset_contains(*ret_fds, fileno(arg_serialization))); return 0; } @@ -2660,7 +2666,7 @@ static bool early_skip_setup_check(int argc, char *argv[]) { for (int i = 1; i < argc; i++) if (streq(argv[i], "--switched-root")) return false; /* If we switched root, don't skip the setup. */ - else if (streq(argv[i], "--deserialize")) + else if (startswith(argv[i], "--deserialize=") || streq(argv[i], "--deserialize")) found_deserialize = true; return found_deserialize; /* When we are deserializing, then we are reexecuting, hence avoid the extensive setup */ diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 27cb0925a..3beb8fd89 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -164,6 +164,14 @@ int manager_serialize( (void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1); } + (void) serialize_item_format(f, + "dump-ratelimit", + USEC_FMT " " USEC_FMT " %u %u", + m->dump_ratelimit.begin, + m->dump_ratelimit.interval, + m->dump_ratelimit.num, + m->dump_ratelimit.burst); + bus_track_serialize(m->subscribed, f, "subscribed"); r = dynamic_user_serialize(m, f, fds); @@ -265,7 +273,7 @@ static void manager_deserialize_uid_refs_one_internal( r = parse_uid(value, &uid); if (r < 0 || uid == 0) { - log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid); + log_debug("Unable to parse UID/GID reference serialization: %s", value); return; } @@ -549,6 +557,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { * remains set until all serialized contents are handled. */ if (deserialize_varlink_sockets) (void) varlink_server_deserialize_one(m->varlink_server, val, fds); + } else if ((val = startswith(l, "dump-ratelimit="))) { + usec_t begin, interval; + unsigned num, burst; + + if (sscanf(val, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4) + log_notice("Failed to parse dump ratelimit, ignoring: %s", val); + else { + /* If we changed the values across versions, flush the counter */ + if (interval != m->dump_ratelimit.interval || burst != m->dump_ratelimit.burst) + m->dump_ratelimit.num = 0; + else + m->dump_ratelimit.num = num; + m->dump_ratelimit.begin = begin; + } + } else { ManagerTimestamp q; diff --git a/src/core/manager.c b/src/core/manager.c index a59afafb5..2bb32ea9c 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -864,6 +864,11 @@ int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager * .test_run_flags = test_run_flags, .default_oom_policy = OOM_STOP, + + .dump_ratelimit = { + .interval = 10 * USEC_PER_MINUTE, + .burst = 10, + }, }; #if ENABLE_EFI @@ -1336,6 +1341,48 @@ static unsigned manager_dispatch_gc_job_queue(Manager *m) { return n; } +static int manager_ratelimit_requeue(sd_event_source *s, uint64_t usec, void *userdata) { + Unit *u = userdata; + + assert(u); + assert(s == u->auto_start_stop_event_source); + + u->auto_start_stop_event_source = sd_event_source_unref(u->auto_start_stop_event_source); + + /* Re-queue to all queues, if the rate limit hit we might have been throttled on any of them. */ + unit_submit_to_stop_when_unneeded_queue(u); + unit_submit_to_start_when_upheld_queue(u); + unit_submit_to_stop_when_bound_queue(u); + + return 0; +} + +static int manager_ratelimit_check_and_queue(Unit *u) { + int r; + + assert(u); + + if (ratelimit_below(&u->auto_start_stop_ratelimit)) + return 1; + + /* Already queued, no need to requeue */ + if (u->auto_start_stop_event_source) + return 0; + + r = sd_event_add_time( + u->manager->event, + &u->auto_start_stop_event_source, + CLOCK_MONOTONIC, + ratelimit_end(&u->auto_start_stop_ratelimit), + 0, + manager_ratelimit_requeue, + u); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to queue timer on event loop: %m"); + + return 0; +} + static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) { unsigned n = 0; Unit *u; @@ -1360,8 +1407,11 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) { /* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the * service being unnecessary after a while. */ - if (!ratelimit_below(&u->auto_start_stop_ratelimit)) { - log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently."); + r = manager_ratelimit_check_and_queue(u); + if (r <= 0) { + log_unit_warning(u, + "Unit not needed anymore, but not stopping since we tried this too often recently.%s", + r == 0 ? " Will retry later." : ""); continue; } @@ -1399,8 +1449,12 @@ static unsigned manager_dispatch_start_when_upheld_queue(Manager *m) { /* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the * service being unnecessary after a while. */ - if (!ratelimit_below(&u->auto_start_stop_ratelimit)) { - log_unit_warning(u, "Unit needs to be started because active unit %s upholds it, but not starting since we tried this too often recently.", culprit->id); + r = manager_ratelimit_check_and_queue(u); + if (r <= 0) { + log_unit_warning(u, + "Unit needs to be started because active unit %s upholds it, but not starting since we tried this too often recently.%s", + culprit->id, + r == 0 ? " Will retry later." : ""); continue; } @@ -1437,8 +1491,12 @@ static unsigned manager_dispatch_stop_when_bound_queue(Manager *m) { /* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the * service being unnecessary after a while. */ - if (!ratelimit_below(&u->auto_start_stop_ratelimit)) { - log_unit_warning(u, "Unit needs to be stopped because it is bound to inactive unit %s it, but not stopping since we tried this too often recently.", culprit->id); + r = manager_ratelimit_check_and_queue(u); + if (r <= 0) { + log_unit_warning(u, + "Unit needs to be stopped because it is bound to inactive unit %s it, but not stopping since we tried this too often recently.%s", + culprit->id, + r == 0 ? " Will retry later." : ""); continue; } @@ -1807,6 +1865,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo /* This block is (optionally) done with the reloading counter bumped */ _unused_ _cleanup_(manager_reloading_stopp) Manager *reloading = NULL; + /* Make sure we don't have a left-over from a previous run */ + if (!serialization) + (void) rm_rf(m->lookup_paths.transient, 0); + /* If we will deserialize make sure that during enumeration this is already known, so we increase the * counter here already */ if (serialization) diff --git a/src/core/manager.h b/src/core/manager.h index 75c16d6e2..3a817b11a 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -461,6 +461,9 @@ struct Manager { struct restrict_fs_bpf *restrict_fs; char *default_smack_process_label; + + /* Dump*() are slow, so always rate limit them to 10 per 10 minutes */ + RateLimit dump_ratelimit; }; static inline usec_t manager_default_timeout_abort_usec(Manager *m) { diff --git a/src/core/mount.c b/src/core/mount.c index 3c5528d55..d82092ac3 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -484,13 +484,16 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, if (e && in_initrd()) { /* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, * it's not technically part of the basic initrd filesystem itself, and so - * shouldn't inherit the default Before=local-fs.target dependency. */ + * shouldn't inherit the default Before=local-fs.target dependency. However, + * these mounts still need to start after local-fs-pre.target, as a sync point + * for things like systemd-hibernate-resume@.service that should start before + * any mounts. */ - after = NULL; + after = SPECIAL_LOCAL_FS_PRE_TARGET; before = isempty(e) ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_INITRD_FS_TARGET; } else if (in_initrd() && path_startswith(m->where, "/sysusr/usr")) { - after = NULL; + after = SPECIAL_LOCAL_FS_PRE_TARGET; before = SPECIAL_INITRD_USR_FS_TARGET; } else if (mount_is_network(p)) { @@ -508,11 +511,9 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p, return r; } - if (after) { - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, /* add_reference= */ true, mask); - if (r < 0) - return r; - } + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, /* add_reference= */ true, mask); + if (r < 0) + return r; return unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, /* add_reference= */ true, mask); diff --git a/src/core/org.freedesktop.systemd1.policy.in b/src/core/org.freedesktop.systemd1.policy.in index 74adeadf3..9e9a20f66 100644 --- a/src/core/org.freedesktop.systemd1.policy.in +++ b/src/core/org.freedesktop.systemd1.policy.in @@ -70,4 +70,14 @@ + + Dump the systemd state without rate limits + Authentication is required to dump the systemd state without rate limits. + + auth_admin + auth_admin + auth_admin_keep + + + diff --git a/src/core/path.c b/src/core/path.c index 3a46e4492..a8144c344 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -10,6 +10,7 @@ #include "dbus-path.h" #include "dbus-unit.h" #include "escape.h" +#include "event-util.h" #include "fd-util.h" #include "glob-util.h" #include "inotify-util.h" @@ -26,10 +27,10 @@ #include "unit.h" static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { - [PATH_DEAD] = UNIT_INACTIVE, + [PATH_DEAD] = UNIT_INACTIVE, [PATH_WAITING] = UNIT_ACTIVE, [PATH_RUNNING] = UNIT_ACTIVE, - [PATH_FAILED] = UNIT_FAILED, + [PATH_FAILED] = UNIT_FAILED, }; static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); @@ -300,6 +301,7 @@ static void path_done(Unit *u) { assert(p); + p->trigger_notify_event_source = sd_event_source_disable_unref(p->trigger_notify_event_source); path_free_specs(p); } @@ -575,6 +577,9 @@ static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify) Unit *trigger; int r; + if (p->trigger_notify_event_source) + (void) event_source_disable(p->trigger_notify_event_source); + /* If the triggered unit is already running, so are we */ trigger = UNIT_TRIGGER(UNIT(p)); if (trigger && !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(trigger))) { @@ -799,8 +804,28 @@ fail: return 0; } -static void path_trigger_notify(Unit *u, Unit *other) { +static void path_trigger_notify_impl(Unit *u, Unit *other, bool on_defer); + +static int path_trigger_notify_on_defer(sd_event_source *s, void *userdata) { + Path *p = ASSERT_PTR(userdata); + Unit *trigger; + + assert(s); + + trigger = UNIT_TRIGGER(UNIT(p)); + if (!trigger) { + log_unit_error(UNIT(p), "Unit to trigger vanished."); + path_enter_dead(p, PATH_FAILURE_RESOURCES); + return 0; + } + + path_trigger_notify_impl(UNIT(p), trigger, /* on_defer = */ true); + return 0; +} + +static void path_trigger_notify_impl(Unit *u, Unit *other, bool on_defer) { Path *p = PATH(u); + int r; assert(u); assert(other); @@ -826,13 +851,46 @@ static void path_trigger_notify(Unit *u, Unit *other) { if (p->state == PATH_RUNNING && UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { - log_unit_debug(UNIT(p), "Got notified about unit deactivation."); - path_enter_waiting(p, false, true); + if (!on_defer) + log_unit_debug(u, "Got notified about unit deactivation."); } else if (p->state == PATH_WAITING && !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { - log_unit_debug(UNIT(p), "Got notified about unit activation."); - path_enter_waiting(p, false, true); + if (!on_defer) + log_unit_debug(u, "Got notified about unit activation."); + } else + return; + + if (on_defer) { + path_enter_waiting(p, /* initial = */ false, /* from_trigger_notify = */ true); + return; } + + /* Do not call path_enter_waiting() directly from path_trigger_notify(), as this may be called by + * job_install() -> job_finish_and_invalidate() -> unit_trigger_notify(), and path_enter_waiting() + * may install another job and will trigger assertion in job_install(). + * https://github.com/systemd/systemd/issues/24577#issuecomment-1522628906 + * Hence, first setup defer event source here, and call path_enter_waiting() slightly later. */ + if (p->trigger_notify_event_source) { + r = sd_event_source_set_enabled(p->trigger_notify_event_source, SD_EVENT_ONESHOT); + if (r < 0) { + log_unit_warning_errno(u, r, "Failed to enable event source for triggering notify: %m"); + path_enter_dead(p, PATH_FAILURE_RESOURCES); + return; + } + } else { + r = sd_event_add_defer(u->manager->event, &p->trigger_notify_event_source, path_trigger_notify_on_defer, p); + if (r < 0) { + log_unit_warning_errno(u, r, "Failed to allocate event source for triggering notify: %m"); + path_enter_dead(p, PATH_FAILURE_RESOURCES); + return; + } + + (void) sd_event_source_set_description(p->trigger_notify_event_source, "path-trigger-notify"); + } +} + +static void path_trigger_notify(Unit *u, Unit *other) { + path_trigger_notify_impl(u, other, /* on_defer = */ false); } static void path_reset_failed(Unit *u) { diff --git a/src/core/path.h b/src/core/path.h index c76103cc1..cb5b66291 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -65,6 +65,8 @@ struct Path { PathResult result; RateLimit trigger_limit; + + sd_event_source *trigger_notify_event_source; }; struct ActivationDetailsPath { diff --git a/src/core/scope.c b/src/core/scope.c index 914d1cc74..197368190 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -115,7 +115,7 @@ static void scope_set_state(Scope *s, ScopeState state) { old_state = s->state; s->state = state; - if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN)) + if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN, SCOPE_RUNNING)) s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source); if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED)) { diff --git a/src/core/service.c b/src/core/service.c index 332e25b37..c05f13c76 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -981,7 +981,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { r = chase_symlinks(s->pid_file, NULL, 0, NULL, &fd); } if (r < 0) - return log_unit_full_errno(UNIT(s), prio, fd, + return log_unit_full_errno(UNIT(s), prio, r, "Can't open PID file %s (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state)); /* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd @@ -2461,6 +2461,7 @@ static void service_run_next_control(Service *s) { s->control_command, timeout, EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL| + (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? EXEC_WRITE_CREDENTIALS : 0)| (IN_SET(s->control_command_id, SERVICE_EXEC_CONDITION, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)| (IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0)| (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_START) ? EXEC_SETENV_MONITOR_RESULT : 0)| @@ -2500,7 +2501,7 @@ static void service_run_next_main(Service *s) { r = service_spawn(s, s->main_command, s->timeout_start_usec, - EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_SETENV_MONITOR_RESULT, + EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS, &pid); if (r < 0) goto fail; @@ -3011,6 +3012,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, } else if (streq(key, "accept-socket")) { Unit *socket; + if (u->type != UNIT_SOCKET) { + log_unit_debug(u, "Failed to deserialize accept-socket: unit is not a socket"); + return 0; + } + r = manager_load_unit(u->manager, value, NULL, NULL, &socket); if (r < 0) log_unit_debug_errno(u, r, "Failed to load accept-socket unit '%s': %m", value); @@ -3523,6 +3529,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { return; s->main_pid = 0; + s->main_pid_known = false; exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status); if (s->main_command) { diff --git a/src/core/slice.c b/src/core/slice.c index 4824a300d..a1c7b459e 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -375,7 +375,7 @@ static int slice_freezer_action(Unit *s, FreezerAction action) { assert(s); assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW)); - if (!slice_freezer_action_supported_by_children(s)) { + if (action == FREEZER_FREEZE && !slice_freezer_action_supported_by_children(s)) { log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice"); return 0; } @@ -386,8 +386,11 @@ static int slice_freezer_action(Unit *s, FreezerAction action) { if (action == FREEZER_FREEZE) r = UNIT_VTABLE(member)->freeze(member); - else + else if (UNIT_VTABLE(member)->thaw) r = UNIT_VTABLE(member)->thaw(member); + else + /* Thawing is requested but no corresponding method is available, ignore. */ + r = 0; if (r < 0) return r; } diff --git a/src/core/system.conf.in b/src/core/system.conf.in index 71a5869ec..a839d0a73 100644 --- a/src/core/system.conf.in +++ b/src/core/system.conf.in @@ -51,7 +51,7 @@ #DefaultStartLimitIntervalSec=10s #DefaultStartLimitBurst=5 #DefaultEnvironment= -#DefaultCPUAccounting=no +#DefaultCPUAccounting=yes #DefaultIOAccounting=no #DefaultIPAccounting=no #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }} diff --git a/src/core/timer.c b/src/core/timer.c index b6810c859..711500313 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -401,12 +401,10 @@ static void timer_enter_waiting(Timer *t, bool time_change) { 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 (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp)) + 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) diff --git a/src/core/transaction.c b/src/core/transaction.c index 8ec853d58..f8886fe4b 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -323,22 +323,28 @@ _pure_ static bool unit_matters_to_anchor(Unit *u, Job *job) { return false; } -static char* merge_unit_ids(const char* unit_log_field, char **pairs) { - char *ans = NULL; - size_t size = 0, next; +static char* merge_unit_ids(const char* unit_log_field, char * const* pairs) { + _cleanup_free_ char *ans = NULL; + size_t size = 0; STRV_FOREACH_PAIR(unit_id, job_type, pairs) { + size_t next; + + if (size > 0) + ans[size - 1] = '\n'; + next = strlen(unit_log_field) + strlen(*unit_id); if (!GREEDY_REALLOC(ans, size + next + 1)) - return mfree(ans); + return NULL; sprintf(ans + size, "%s%s", unit_log_field, *unit_id); - if (*(unit_id+1)) - ans[size + next] = '\n'; size += next + 1; } - return ans; + if (!ans) + return strdup(""); + + return TAKE_PTR(ans); } static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) { @@ -394,7 +400,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "Found %s on %s/%s", unit_id == array ? "ordering cycle" : "dependency", *unit_id, *job_type), - "%s", unit_ids); + "%s", strna(unit_ids)); if (delete) { const char *status; @@ -404,7 +410,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "Job %s/%s deleted to break ordering cycle starting with %s/%s", delete->unit->id, job_type_to_string(delete->type), j->unit->id, job_type_to_string(j->type)), - "%s", unit_ids); + "%s", strna(unit_ids)); if (log_get_show_color()) status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL; @@ -423,7 +429,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi log_struct(LOG_ERR, LOG_UNIT_MESSAGE(j->unit, "Unable to break cycle starting with %s/%s", j->unit->id, job_type_to_string(j->type)), - "%s", unit_ids); + "%s", strna(unit_ids)); return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details."); @@ -656,7 +662,7 @@ static int transaction_apply( /* j has been merged into a previously installed job */ if (tr->anchor_job == j) tr->anchor_job = installed_job; - hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); + hashmap_remove_value(m->jobs, UINT32_TO_PTR(j->id), j); job_free(j); j = installed_job; } @@ -677,7 +683,7 @@ static int transaction_apply( rollback: HASHMAP_FOREACH(j, tr->jobs) - hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); + hashmap_remove_value(m->jobs, UINT32_TO_PTR(j->id), j); return r; } diff --git a/src/core/unit.c b/src/core/unit.c index 7096e1fa4..d896efe9c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -672,6 +672,8 @@ Unit* unit_free(Unit *u) { if (!u) return NULL; + sd_event_source_disable_unref(u->auto_start_stop_event_source); + u->transient_file = safe_fclose(u->transient_file); if (!MANAGER_IS_RELOADING(u->manager)) @@ -902,7 +904,7 @@ static int unit_reserve_dependencies(Unit *u, Unit *other) { /* Let's reserve some space in the dependency hashmaps so that later on merging the units cannot * fail. * - * First make some room in the per dependency type hashmaps. Using the summed size of both unit's + * First make some room in the per dependency type hashmaps. Using the summed size of both units' * hashmaps is an estimate that is likely too high since they probably use some of the same * types. But it's never too low, and that's all we need. */ @@ -1543,7 +1545,8 @@ static int unit_add_mount_dependencies(Unit *u) { static int unit_add_oomd_dependencies(Unit *u) { CGroupContext *c; - bool wants_oomd; + CGroupMask mask; + int r; assert(u); @@ -1554,10 +1557,20 @@ static int unit_add_oomd_dependencies(Unit *u) { if (!c) return 0; - wants_oomd = (c->moom_swap == MANAGED_OOM_KILL || c->moom_mem_pressure == MANAGED_OOM_KILL); + bool wants_oomd = c->moom_swap == MANAGED_OOM_KILL || c->moom_mem_pressure == MANAGED_OOM_KILL; if (!wants_oomd) return 0; + if (!cg_all_unified()) + return 0; + + r = cg_mask_supported(&mask); + if (r < 0) + return log_debug_errno(r, "Failed to determine supported controllers: %m"); + + if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY)) + return 0; + return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, "systemd-oomd.service", true, UNIT_DEPENDENCY_FILE); } @@ -6011,7 +6024,9 @@ int activation_details_deserialize(const char *key, const char *value, Activatio return -EINVAL; t = unit_type_from_string(value); - if (t == _UNIT_TYPE_INVALID) + /* The activation details vtable has defined ops only for path + * and timer units */ + if (!IN_SET(t, UNIT_PATH, UNIT_TIMER)) return -EINVAL; *details = malloc0(activation_details_vtable[t]->object_size); diff --git a/src/core/unit.h b/src/core/unit.h index 3bc7de3d1..65a1d26fe 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -347,6 +347,7 @@ typedef struct Unit { /* Make sure we never enter endless loops with the StopWhenUnneeded=, BindsTo=, Uphold= logic */ RateLimit auto_start_stop_ratelimit; + sd_event_source *auto_start_stop_event_source; /* Reference to a specific UID/GID */ uid_t ref_uid; diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index ea3d8c415..b9c5f3ad0 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -48,6 +48,7 @@ #include "sync-util.h" #include "tmpfile-util.h" #include "uid-alloc-range.h" +#include "unaligned.h" #include "user-util.h" /* The maximum size up to which we process coredumps. We use 1G on 32bit systems, and 32G on 64bit systems */ @@ -339,95 +340,65 @@ static int make_filename(const Context *context, char **ret) { return 0; } -static int parse_auxv64( - const uint64_t *auxv, - size_t size_bytes, - int *at_secure, - uid_t *uid, - uid_t *euid, - gid_t *gid, - gid_t *egid) { +#define _DEFINE_PARSE_AUXV(size, type, unaligned_read) \ + static int parse_auxv##size( \ + const void *auxv, \ + size_t size_bytes, \ + int *at_secure, \ + uid_t *uid, \ + uid_t *euid, \ + gid_t *gid, \ + gid_t *egid) { \ + \ + assert(auxv || size_bytes == 0); \ + \ + if (size_bytes % (2 * sizeof(type)) != 0) \ + return log_warning_errno(SYNTHETIC_ERRNO(EIO), \ + "Incomplete auxv structure (%zu bytes).", \ + size_bytes); \ + \ + size_t words = size_bytes / sizeof(type); \ + \ + /* Note that we set output variables even on error. */ \ + \ + for (size_t i = 0; i + 1 < words; i += 2) { \ + type key, val; \ + \ + key = unaligned_read((uint8_t*) auxv + i * sizeof(type)); \ + val = unaligned_read((uint8_t*) auxv + (i + 1) * sizeof(type)); \ + \ + switch (key) { \ + case AT_SECURE: \ + *at_secure = val != 0; \ + break; \ + case AT_UID: \ + *uid = val; \ + break; \ + case AT_EUID: \ + *euid = val; \ + break; \ + case AT_GID: \ + *gid = val; \ + break; \ + case AT_EGID: \ + *egid = val; \ + break; \ + case AT_NULL: \ + if (val != 0) \ + goto error; \ + return 0; \ + } \ + } \ + error: \ + return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), \ + "AT_NULL terminator not found, cannot parse auxv structure."); \ + } - assert(auxv || size_bytes == 0); +#define DEFINE_PARSE_AUXV(size)\ + _DEFINE_PARSE_AUXV(size, uint##size##_t, unaligned_read_ne##size) - if (size_bytes % (2 * sizeof(uint64_t)) != 0) - return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes); - - size_t words = size_bytes / sizeof(uint64_t); - - /* Note that we set output variables even on error. */ - - for (size_t i = 0; i + 1 < words; i += 2) - switch (auxv[i]) { - case AT_SECURE: - *at_secure = auxv[i + 1] != 0; - break; - case AT_UID: - *uid = auxv[i + 1]; - break; - case AT_EUID: - *euid = auxv[i + 1]; - break; - case AT_GID: - *gid = auxv[i + 1]; - break; - case AT_EGID: - *egid = auxv[i + 1]; - break; - case AT_NULL: - if (auxv[i + 1] != 0) - goto error; - return 0; - } - error: - return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), - "AT_NULL terminator not found, cannot parse auxv structure."); -} - -static int parse_auxv32( - const uint32_t *auxv, - size_t size_bytes, - int *at_secure, - uid_t *uid, - uid_t *euid, - gid_t *gid, - gid_t *egid) { - - assert(auxv || size_bytes == 0); - - size_t words = size_bytes / sizeof(uint32_t); - - if (size_bytes % (2 * sizeof(uint32_t)) != 0) - return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes); - - /* Note that we set output variables even on error. */ - - for (size_t i = 0; i + 1 < words; i += 2) - switch (auxv[i]) { - case AT_SECURE: - *at_secure = auxv[i + 1] != 0; - break; - case AT_UID: - *uid = auxv[i + 1]; - break; - case AT_EUID: - *euid = auxv[i + 1]; - break; - case AT_GID: - *gid = auxv[i + 1]; - break; - case AT_EGID: - *egid = auxv[i + 1]; - break; - case AT_NULL: - if (auxv[i + 1] != 0) - goto error; - return 0; - } - error: - return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), - "AT_NULL terminator not found, cannot parse auxv structure."); -} +DEFINE_PARSE_AUXV(32); +DEFINE_PARSE_AUXV(64); static int grant_user_access(int core_fd, const Context *context) { int at_secure = -1; @@ -464,11 +435,11 @@ static int grant_user_access(int core_fd, const Context *context) { "Core file has non-native endianness, not adjusting permissions."); if (elf[EI_CLASS] == ELFCLASS64) - r = parse_auxv64((const uint64_t*) context->meta[META_PROC_AUXV], + r = parse_auxv64(context->meta[META_PROC_AUXV], context->meta_size[META_PROC_AUXV], &at_secure, &uid, &euid, &gid, &egid); else - r = parse_auxv32((const uint32_t*) context->meta[META_PROC_AUXV], + r = parse_auxv32(context->meta[META_PROC_AUXV], context->meta_size[META_PROC_AUXV], &at_secure, &uid, &euid, &gid, &egid); if (r < 0) diff --git a/src/cryptenroll/cryptenroll-list.c b/src/cryptenroll/cryptenroll-list.c index 62688da3d..d21df7123 100644 --- a/src/cryptenroll/cryptenroll-list.c +++ b/src/cryptenroll/cryptenroll-list.c @@ -5,12 +5,13 @@ #include "format-table.h" #include "parse-util.h" -int list_enrolled(struct crypt_device *cd) { +struct keyslot_metadata { + int slot; + const char *type; +}; - struct keyslot_metadata { - int slot; - const char *type; - } *keyslot_metadata = NULL; +int list_enrolled(struct crypt_device *cd) { + _cleanup_free_ struct keyslot_metadata *keyslot_metadata = NULL; _cleanup_(table_unrefp) Table *t = NULL; size_t n_keyslot_metadata = 0; int slot_max, r; diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c index 9b7c8b540..2e2efcf6f 100644 --- a/src/cryptenroll/cryptenroll-password.c +++ b/src/cryptenroll/cryptenroll-password.c @@ -81,7 +81,7 @@ int enroll_password( if (r < 0) return log_error_errno(r, "Failed to check password for quality: %m"); if (r == 0) - log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", error); + log_warning("Specified password does not pass quality checks (%s), proceeding anyway.", error); keyslot = crypt_keyslot_add_by_volume_key( cd, diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index 6a9170f00..ab63900cb 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -394,15 +394,15 @@ static int parse_argv(int argc, char *argv[]) { if (arg_wipe_slots_scope != WIPE_ALL) /* if "all" was specified before, that wins */ arg_wipe_slots_scope = WIPE_EMPTY_PASSPHRASE; } else if (streq(slot, "password")) - arg_wipe_slots_mask = 1U << ENROLL_PASSWORD; + arg_wipe_slots_mask |= 1U << ENROLL_PASSWORD; else if (streq(slot, "recovery")) - arg_wipe_slots_mask = 1U << ENROLL_RECOVERY; + arg_wipe_slots_mask |= 1U << ENROLL_RECOVERY; else if (streq(slot, "pkcs11")) - arg_wipe_slots_mask = 1U << ENROLL_PKCS11; + arg_wipe_slots_mask |= 1U << ENROLL_PKCS11; else if (streq(slot, "fido2")) - arg_wipe_slots_mask = 1U << ENROLL_FIDO2; + arg_wipe_slots_mask |= 1U << ENROLL_FIDO2; else if (streq(slot, "tpm2")) - arg_wipe_slots_mask = 1U << ENROLL_TPM2; + arg_wipe_slots_mask |= 1U << ENROLL_TPM2; else { int *a; diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 595434ab5..ba76e1b0a 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -353,6 +353,7 @@ static int run(int argc, char *argv[]) { if (r == 0) { char dash_c[STRLEN("-C") + DECIMAL_STR_MAX(int) + 1]; int progress_socket = -1; + _cleanup_free_ char *fsck_path = NULL; const char *cmdline[9]; int i = 0; @@ -373,7 +374,13 @@ static int run(int argc, char *argv[]) { } else dash_c[0] = 0; - cmdline[i++] = "/sbin/fsck"; + r = find_executable("fsck", &fsck_path); + if (r < 0) { + log_error_errno(r, "Cannot find fsck binary: %m"); + _exit(FSCK_OPERATIONAL_ERROR); + } + + cmdline[i++] = fsck_path; cmdline[i++] = arg_repair; cmdline[i++] = "-T"; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index e76de45a0..63f0f369f 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -942,7 +942,7 @@ static int add_sysroot_usr_mount(void) { } if (isempty(arg_usr_what)) { - log_debug("Could not find a usr= entry on the kernel command line."); + log_debug("Could not find a mount.usr= entry on the kernel command line."); return 0; } diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 30639b3ad..2e60b82a1 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -565,7 +565,7 @@ static int add_partition_root_rw(DissectedPartition *p) { path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf"); r = write_string_file(path, - "# Automatically generated by systemd-gpt-generator\n\n" + "# Automatically generated by systemd-gpt-auto-generator\n\n" "[Service]\n" "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW|WRITE_STRING_FILE_MKDIR_0755); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 19be18640..40aa204f7 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -2692,8 +2692,6 @@ static int home_dispatch_acquire(Home *h, Operation *o) { assert(o); assert(o->type == OPERATION_ACQUIRE); - assert(!h->current_operation); - switch (home_get_state(h)) { case HOME_UNFIXATED: @@ -2729,6 +2727,8 @@ static int home_dispatch_acquire(Home *h, Operation *o) { return 0; } + assert(!h->current_operation); + r = home_ratelimit(h, &error); if (r >= 0) r = call(h, o->secret, for_state, &error); diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 61ef97904..9075e3e08 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -1616,7 +1616,7 @@ void manager_revalidate_image(Manager *m, Home *h) { assert(h); /* Frees an automatically discovered image, if it's synthetic and its image disappeared. Unmounts any - * image if it's mounted but it's image vanished. */ + * image if it's mounted but its image vanished. */ if (h->current_operation || !ordered_set_isempty(h->pending_operations)) return; diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 97fb5a105..1af156ee1 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -213,6 +213,7 @@ static int block_get_size_by_path(const char *path, uint64_t *ret) { static int run_fsck(const char *node, const char *fstype) { int r, exit_status; pid_t fsck_pid; + _cleanup_free_ char *fsck_path = NULL; assert(node); assert(fstype); @@ -225,6 +226,14 @@ static int run_fsck(const char *node, const char *fstype) { return 0; } + r = find_executable("fsck", &fsck_path); + /* We proceed anyway if we can't determine whether the fsck + * binary for some specific fstype exists, + * but the lack of the main fsck binary should be considered + * an error. */ + if (r < 0) + return log_error_errno(r, "Cannot find fsck binary: %m"); + r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, &fsck_pid); @@ -232,7 +241,7 @@ static int run_fsck(const char *node, const char *fstype) { return r; if (r == 0) { /* Child */ - execl("/sbin/fsck", "/sbin/fsck", "-aTl", node, NULL); + execl(fsck_path, fsck_path, "-aTl", node, NULL); log_open(); log_error_errno(errno, "Failed to execute fsck: %m"); _exit(FSCK_OPERATIONAL_ERROR); @@ -1230,7 +1239,7 @@ int home_setup_luks( PasswordCache *cache, UserRecord **ret_luks_home) { - sd_id128_t found_partition_uuid, found_fs_uuid, found_luks_uuid = SD_ID128_NULL; + sd_id128_t found_partition_uuid, found_fs_uuid = SD_ID128_NULL, found_luks_uuid = SD_ID128_NULL; _cleanup_(user_record_unrefp) UserRecord *luks_home = NULL; _cleanup_(erase_and_freep) void *volume_key = NULL; size_t volume_key_size = 0; diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index 8b4141657..3f8627678 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -140,7 +140,7 @@ static int acquire_user_record( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *generic_field = NULL, *json_copy = NULL; - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd-home", &bus); if (r != PAM_SUCCESS) return r; @@ -513,7 +513,7 @@ static int acquire_home( if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0) return PAM_SUCCESS; - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd-home", &bus); if (r != PAM_SUCCESS) return r; @@ -727,7 +727,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( r = acquire_home(handle, /* please_authenticate = */ false, suspend_please, debug); if (r == PAM_USER_UNKNOWN) /* Not managed by us? Don't complain. */ - return PAM_SUCCESS; + goto success; /* Need to free the bus resource, as acquire_home() takes a reference. */ if (r != PAM_SUCCESS) return r; @@ -741,10 +741,11 @@ _public_ PAM_EXTERN int pam_sm_open_session( return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: @PAMERR@"); +success: /* Let's release the D-Bus connection, after all the session might live quite a long time, and we are * not going to process the bus connection in that time, so let's better close before the daemon * kicks us off because we are not processing anything. */ - (void) pam_release_bus_connection(handle); + (void) pam_release_bus_connection(handle, "pam-systemd-home"); return PAM_SUCCESS; } @@ -784,7 +785,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( if (r != PAM_SUCCESS) return r; - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd-home", &bus); if (r != PAM_SUCCESS) return r; @@ -943,7 +944,7 @@ _public_ PAM_EXTERN int pam_sm_chauthtok( if (debug) pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed account management"); - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd-home", &bus); if (r != PAM_SUCCESS) return r; diff --git a/src/journal-remote/fuzz-journal-remote.c b/src/journal-remote/fuzz-journal-remote.c index db10c2b01..38940cc57 100644 --- a/src/journal-remote/fuzz-journal-remote.c +++ b/src/journal-remote/fuzz-journal-remote.c @@ -13,16 +13,19 @@ #include "journal-remote.h" #include "logs-show.h" #include "memfd-util.h" +#include "path-util.h" +#include "rm-rf.h" #include "strv.h" +#include "tmpfile-util.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - int fdin; - void *mem; - _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journal-remote.XXXXXX.journal"; - _cleanup_close_ int fdout = -1; + _cleanup_close_ int fdin_close = -1, fdout = -1; + _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL; + _cleanup_(unlink_and_freep) char *name = NULL; _cleanup_(sd_journal_closep) sd_journal *j = NULL; _cleanup_(journal_remote_server_destroy) RemoteServer s = {}; - int r; + void *mem; + int fdin, r; if (outside_size_range(size, 3, 65536)) return 0; @@ -30,7 +33,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (!getenv("SYSTEMD_LOG_LEVEL")) log_set_max_level(LOG_ERR); - fdin = memfd_new_and_map("fuzz-journal-remote", size, &mem); + assert_se(mkdtemp_malloc("/tmp/fuzz-journal-remote-XXXXXX", &tmp) >= 0); + assert_se(name = path_join(tmp, "fuzz-journal-remote.XXXXXX.journal")); + + fdin = fdin_close = memfd_new_and_map("fuzz-journal-remote", size, &mem); if (fdin < 0) return log_error_errno(fdin, "memfd_new_and_map() failed: %m"); @@ -50,10 +56,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { } r = journal_remote_add_source(&s, fdin, (char*) "fuzz-data", false); - if (r < 0) { - safe_close(fdin); + if (r < 0) return r; - } + TAKE_FD(fdin_close); assert(r > 0); while (s.active) diff --git a/src/journal/cat.c b/src/journal/cat.c index 0c2c0d615..350b8056a 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -73,6 +73,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) switch (c) { diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 98134d0fa..6f7654898 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -542,11 +542,6 @@ static int parse_argv(int argc, char *argv[]) { case 'f': arg_follow = true; - - arg_boot = true; - arg_boot_id = SD_ID128_NULL; - arg_boot_offset = 0; - break; case 'o': @@ -1041,9 +1036,18 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } - if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT) + if (arg_no_tail) + arg_lines = ARG_LINES_ALL; + + if (arg_follow && !arg_since_set && arg_lines == ARG_LINES_DEFAULT) arg_lines = 10; + if (arg_follow && !arg_merge && !arg_boot) { + arg_boot = true; + arg_boot_id = SD_ID128_NULL; + arg_boot_offset = 0; + } + if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root + !!arg_image > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=."); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index b4ffd38f8..6faf48db2 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -2019,7 +2019,7 @@ static int vl_method_synchronize(Varlink *link, JsonVariant *parameters, Varlink if (json_variant_elements(parameters) > 0) return varlink_error_invalid_parameter(link, parameters); - log_info("Received client request to rotate journal."); + log_info("Received client request to sync journal."); /* We don't do the main work now, but instead enqueue a deferred event loop job which will do * it. That job is scheduled at low priority, so that we return from this method call only after all diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index b3ae4b814..81e37b676 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -72,7 +72,7 @@ static void append_number(ManagedJournalFile *f, int n, uint64_t *seqnum) { static void test_check_number(sd_journal *j, int n) { const void *d; - _cleanup_free_ char *k; + _cleanup_free_ char *k = NULL; size_t l; int x; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 8344dc4f4..787dcf1a5 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -189,7 +189,7 @@ static int check_options(uint8_t code, uint8_t len, const void *option, void *us int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) { size_t size; - _cleanup_free_ DHCPPacket *discover; + _cleanup_free_ DHCPPacket *discover = NULL; uint16_t ip_check, udp_check; assert_se(s >= 0); diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 4468b45dd..5951e0899 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -661,8 +661,8 @@ static int has_cap(sd_bus_creds *c, size_t offset, int capability) { if ((unsigned) capability > lc) return 0; - /* If the last cap is 63, then there are 64 caps defined, and we need 2 entries รก 32bit hence. * - * If the last cap is 64, then there are 65 caps defined, and we need 3 entries รก 32bit hence. */ + /* If the last cap is 63, then there are 64 caps defined, and we need 2 entries ร  32bit hence. * + * If the last cap is 64, then there are 65 caps defined, and we need 3 entries ร  32bit hence. */ sz = DIV_ROUND_UP(lc+1, 32LU); return !!(c->capability[offset * sz + CAP_TO_INDEX((uint32_t) capability)] & CAP_TO_MASK_CORRECTED((uint32_t) capability)); diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 51673ad1c..d486e17fc 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -361,7 +361,7 @@ bool path_complex_pattern(const char *pattern, const char *value) _pure_; bool namespace_simple_pattern(const char *pattern, const char *value) _pure_; bool path_simple_pattern(const char *pattern, const char *value) _pure_; -int bus_message_type_from_string(const char *s, uint8_t *u) _pure_; +int bus_message_type_from_string(const char *s, uint8_t *u); const char *bus_message_type_to_string(uint8_t u) _pure_; #define error_name_is_valid interface_name_is_valid diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index d9c52d64c..3262c07c6 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1324,12 +1324,21 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void * into the empty string */ p = strempty(p); - _fallthrough_; + if (!utf8_is_valid(p)) + return -EINVAL; + + align = 4; + sz = 4 + strlen(p) + 1; + break; + case SD_BUS_TYPE_OBJECT_PATH: if (!p) return -EINVAL; + if (!object_path_is_valid(p)) + return -EINVAL; + align = 4; sz = 4 + strlen(p) + 1; break; @@ -1338,6 +1347,9 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void p = strempty(p); + if (!signature_is_valid(p, /* allow_dict_entry = */ true)) + return -EINVAL; + align = 1; sz = 1 + strlen(p) + 1; break; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index bc716afab..d6a3177d3 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -37,6 +37,7 @@ #include "macro.h" #include "memory-util.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -4155,8 +4156,6 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) { assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(description, -EINVAL); - assert_return(bus->description, -ENXIO); - assert_return(!bus_pid_changed(bus), -ECHILD); if (bus->description) *description = bus->description; @@ -4165,7 +4164,7 @@ _public_ int sd_bus_get_description(sd_bus *bus, const char **description) { else if (bus->is_user) *description = "user"; else - *description = NULL; + return -ENXIO; return 0; } diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index a583a37da..c215b924c 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -281,11 +281,10 @@ static int sound_device_compare(const char *devpath_a, const char *devpath_b) { * kernel makes this guarantee when creating those devices, and hence we should too when * enumerating them. */ - sound_a = strstr(devpath_a, "/sound/card"); + sound_a = strstrafter(devpath_a, "/sound/card"); if (!sound_a) return 0; - sound_a += STRLEN("/sound/card"); sound_a = strchr(devpath_a, '/'); if (!sound_a) return 0; diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index ff4209eff..24bc32f17 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -266,7 +266,7 @@ static void test_sd_device_enumerator_filter_subsystem_one( static bool test_sd_device_enumerator_filter_subsystem_trial(void) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - _cleanup_(hashmap_freep) Hashmap *subsystems; + _cleanup_(hashmap_freep) Hashmap *subsystems = NULL; unsigned n_new_dev = 0, n_removed_dev = 0; sd_device *d; Hashmap *h; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index b678be5fe..aee2ed528 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -19,6 +19,7 @@ #include "macro.h" #include "memory-util.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "prioq.h" #include "process-util.h" #include "set.h" @@ -2222,7 +2223,6 @@ _public_ int sd_event_source_set_description(sd_event_source *s, const char *des _public_ int sd_event_source_get_description(sd_event_source *s, const char **description) { assert_return(s, -EINVAL); assert_return(description, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); if (!s->description) return -ENXIO; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 246658d02..33cd1c0cc 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -506,7 +506,7 @@ static void test_inotify_one(unsigned n_create_events) { for (i = 0; i < n_create_events; i++) { char buf[DECIMAL_STR_MAX(unsigned)+1]; - _cleanup_free_ char *z; + _cleanup_free_ char *z = NULL; xsprintf(buf, "%u", i); assert_se(z = path_join(p, buf)); diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 5e9ec2b5f..07e2ce002 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -14,6 +14,7 @@ #include "io-util.h" #include "macro.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "random-util.h" #include "user-util.h" #include "util.h" diff --git a/src/libsystemd/sd-journal/catalog.c b/src/libsystemd/sd-journal/catalog.c index b988ee3bb..5e7649cad 100644 --- a/src/libsystemd/sd-journal/catalog.c +++ b/src/libsystemd/sd-journal/catalog.c @@ -145,7 +145,8 @@ static int finish_item( char *payload, size_t payload_size) { _cleanup_free_ CatalogItem *i = NULL; - _cleanup_free_ char *prev = NULL, *combined = NULL; + _cleanup_free_ char *combined = NULL; + char *prev; assert(h); assert(payload); @@ -171,6 +172,7 @@ static int finish_item( if (ordered_hashmap_update(h, i, combined) < 0) return log_oom(); combined = NULL; + free(prev); } else { /* A new item */ combined = memdup(payload, payload_size + 1); @@ -477,7 +479,7 @@ int catalog_update(const char* database, const char* root, const char* const* di n = 0; ORDERED_HASHMAP_FOREACH_KEY(payload, i, h) { - log_debug("Found " SD_ID128_FORMAT_STR ", language %s", + log_trace("Found " SD_ID128_FORMAT_STR ", language %s", SD_ID128_FORMAT_VAL(i->id), isempty(i->language) ? "C" : i->language); diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 5c414afca..7b0581289 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -838,7 +838,7 @@ static int check_object(JournalFile *f, Object *o, uint64_t offset) { } case OBJECT_ENTRY_ARRAY: { - uint64_t sz; + uint64_t sz, next; sz = le64toh(READ_NOW(o->object.size)); if (sz < offsetof(Object, entry_array.items) || @@ -848,11 +848,12 @@ static int check_object(JournalFile *f, Object *o, uint64_t offset) { "Invalid object entry array size: %" PRIu64 ": %" PRIu64, sz, offset); - - if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) + /* Here, we request that the offset of each entry array object is in strictly increasing order. */ + next = le64toh(o->entry_array.next_entry_array_offset); + if (!VALID64(next) || (next > 0 && next <= offset)) return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), - "Invalid object entry array next_entry_array_offset: " OFSfmt ": %" PRIu64, - le64toh(o->entry_array.next_entry_array_offset), + "Invalid object entry array next_entry_array_offset: %" PRIu64 ": %" PRIu64, + next, offset); break; @@ -2410,7 +2411,8 @@ static int bump_entry_array( if (direction == DIRECTION_DOWN) { assert(o); - return le64toh(o->entry_array.next_entry_array_offset); + *ret = le64toh(o->entry_array.next_entry_array_offset); + return 0; } /* Entry array chains are a singly linked list, so to find the previous array in the chain, we have @@ -3986,8 +3988,8 @@ int journal_file_dispose(int dir_fd, const char *fname) { int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p) { _cleanup_free_ EntryItem *items_alloc = NULL; EntryItem *items; - uint64_t q, n, xor_hash = 0; - const sd_id128_t *boot_id; + uint64_t n, m = 0, xor_hash = 0; + sd_id128_t boot_id; dual_timestamp ts; int r; @@ -4003,9 +4005,11 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 .monotonic = le64toh(o->entry.monotonic), .realtime = le64toh(o->entry.realtime), }; - boot_id = &o->entry.boot_id; + boot_id = o->entry.boot_id; n = journal_file_entry_n_items(from, o); + if (n == 0) + return 0; if (n < ALLOCA_MAX / sizeof(EntryItem) / 2) items = newa(EntryItem, n); @@ -4018,7 +4022,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 } for (uint64_t i = 0; i < n; i++) { - uint64_t h; + uint64_t h, q; void *data; size_t l; Object *u; @@ -4045,7 +4049,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 else xor_hash ^= le64toh(u->data.hash); - items[i] = (EntryItem) { + items[m++] = (EntryItem) { .object_offset = h, .hash = le64toh(u->data.hash), }; @@ -4058,7 +4062,10 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 return r; } - r = journal_file_append_entry_internal(to, &ts, boot_id, xor_hash, items, n, NULL, NULL, NULL); + if (m == 0) + return 0; + + r = journal_file_append_entry_internal(to, &ts, &boot_id, xor_hash, items, m, NULL, NULL, NULL); if (mmap_cache_fd_got_sigbus(to->cache_fd)) return -EIO; diff --git a/src/libsystemd/sd-journal/journal-vacuum.c b/src/libsystemd/sd-journal/journal-vacuum.c index eac350020..23497af28 100644 --- a/src/libsystemd/sd-journal/journal-vacuum.c +++ b/src/libsystemd/sd-journal/journal-vacuum.c @@ -158,6 +158,8 @@ int journal_directory_vacuum( if (!S_ISREG(st.st_mode)) continue; + size = 512UL * (uint64_t) st.st_blocks; + q = strlen(de->d_name); if (endswith(de->d_name, ".journal")) { @@ -167,6 +169,7 @@ int journal_directory_vacuum( if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) { n_active_files++; + sum += size; continue; } @@ -174,6 +177,7 @@ int journal_directory_vacuum( de->d_name[q-8-16-1-16-1] != '-' || de->d_name[q-8-16-1-16-1-32-1] != '@') { n_active_files++; + sum += size; continue; } @@ -186,11 +190,13 @@ int journal_directory_vacuum( de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { n_active_files++; + sum += size; continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { n_active_files++; + sum += size; continue; } @@ -206,12 +212,14 @@ int journal_directory_vacuum( if (q < 1 + 16 + 1 + 16 + 8 + 1) { n_active_files++; + sum += size; continue; } if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') { n_active_files++; + sum += size; continue; } @@ -223,6 +231,7 @@ int journal_directory_vacuum( if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { n_active_files++; + sum += size; continue; } @@ -233,8 +242,6 @@ int journal_directory_vacuum( continue; } - size = 512UL * (uint64_t) st.st_blocks; - r = journal_file_empty(dirfd(d), p); if (r < 0) { log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p); diff --git a/src/libsystemd/sd-journal/test-catalog.c b/src/libsystemd/sd-journal/test-catalog.c index ad0622117..9a159150b 100644 --- a/src/libsystemd/sd-journal/test-catalog.c +++ b/src/libsystemd/sd-journal/test-catalog.c @@ -28,7 +28,7 @@ static const char *no_catalog_dirs[] = { static OrderedHashmap* test_import(const char* contents, ssize_t size, int code) { _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-catalog.XXXXXX"; - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; OrderedHashmap *h; if (size < 0) diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 5362ec0fa..ba88168f0 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -22,6 +22,7 @@ #include "list.h" #include "memory-util.h" #include "missing_syscall.h" +#include "missing_threads.h" #include "process-util.h" #include "resolve-private.h" #include "socket-util.h" diff --git a/src/libudev/test-libudev.c b/src/libudev/test-libudev.c index 94d34b1ae..839a6a1a7 100644 --- a/src/libudev/test-libudev.c +++ b/src/libudev/test-libudev.c @@ -91,7 +91,7 @@ static void print_device(struct udev_device *device) { } static void test_device(struct udev *udev, const char *syspath) { - _cleanup_(udev_device_unrefp) struct udev_device *device; + _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; log_info("/* %s, device %s */", __func__, syspath); device = udev_device_new_from_syspath(udev, syspath); @@ -102,7 +102,7 @@ static void test_device(struct udev *udev, const char *syspath) { } static void test_device_parents(struct udev *udev, const char *syspath) { - _cleanup_(udev_device_unrefp) struct udev_device *device; + _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; struct udev_device *device_parent; log_info("/* %s, device %s */", __func__, syspath); @@ -172,7 +172,7 @@ static int enumerate_print_list(struct udev_enumerate *enumerate) { static void test_monitor(struct udev *udev) { _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor; - _cleanup_close_ int fd_ep; + _cleanup_close_ int fd_ep = -EBADF; int fd_udev; struct epoll_event ep_udev = { .events = EPOLLIN, diff --git a/src/locale/localed-util.c b/src/locale/localed-util.c index dd2bbf5bf..4d021fb00 100644 --- a/src/locale/localed-util.c +++ b/src/locale/localed-util.c @@ -687,6 +687,7 @@ static int locale_gen_locale_supported(const char *locale_entry) { for (;;) { _cleanup_free_ char *line = NULL; + char *l; r = read_line(f, LONG_LINE_MAX, &line); if (r < 0) @@ -694,8 +695,8 @@ static int locale_gen_locale_supported(const char *locale_entry) { if (r == 0) return 0; - line = strstrip(line); - if (strcaseeq_ptr(line, locale_entry)) + l = strstrip(line); + if (strcaseeq_ptr(l, locale_entry)) return 1; } } @@ -773,14 +774,13 @@ int locale_gen_enable_locale(const char *locale) { continue; } - line = strstrip(line); - if (isempty(line)) { + line_locale = strstrip(line); + if (isempty(line_locale)) { fputc('\n', fw); first_line = false; continue; } - line_locale = line; if (line_locale[0] == '#') line_locale = strstrip(line_locale + 1); else if (strcaseeq_ptr(line_locale, locale_entry)) diff --git a/src/login/inhibit.c b/src/login/inhibit.c index 211af404b..72453b757 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -210,6 +210,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0) switch (c) { diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 16612ddf1..26caa2b5b 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -17,6 +17,7 @@ #include "io-util.h" #include "logind-dbus.h" #include "logind-inhibit.h" +#include "missing_threads.h" #include "mkdir-label.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index a288b3602..4190f9339 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -815,7 +815,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( /* Talk to logind over the message bus */ - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd", &bus); if (r != PAM_SUCCESS) return r; @@ -979,7 +979,7 @@ success: /* Let's release the D-Bus connection, after all the session might live quite a long time, and we are * not going to use the bus connection in that time, so let's better close before the daemon kicks us * off because we are not processing anything. */ - (void) pam_release_bus_connection(handle); + (void) pam_release_bus_connection(handle, "pam-systemd"); return PAM_SUCCESS; } @@ -1021,7 +1021,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( /* Before we go and close the FIFO we need to tell logind that this is a clean session * shutdown, so that it doesn't just go and slaughter us immediately after closing the fd */ - r = pam_acquire_bus_connection(handle, &bus); + r = pam_acquire_bus_connection(handle, "pam-systemd", &bus); if (r != PAM_SUCCESS) return r; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 14085f739..a258a18f7 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -684,9 +684,7 @@ static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line } static int show_machine(int argc, char *argv[], void *userdata) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; bool properties, new_line = false; sd_bus *bus = ASSERT_PTR(userdata); int r = 0; @@ -705,6 +703,7 @@ static int show_machine(int argc, char *argv[], void *userdata) { } for (int i = 1; i < argc; i++) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *path = NULL; r = bus_call_method(bus, bus_machine_mgr, "GetMachine", &error, &reply, "s", argv[i]); @@ -981,9 +980,7 @@ static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) } static int show_image(int argc, char *argv[], void *userdata) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; bool properties, new_line = false; sd_bus *bus = ASSERT_PTR(userdata); int r = 0; @@ -1006,6 +1003,7 @@ static int show_image(int argc, char *argv[], void *userdata) { } for (int i = 1; i < argc; i++) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *path = NULL; r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, &reply, "s", argv[i]); @@ -2529,6 +2527,10 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; + for (;;) { static const char option_string[] = "-hp:als:H:M:qn:o:E:"; diff --git a/src/machine/operation.c b/src/machine/operation.c index c97b29aba..335f47c9e 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -15,7 +15,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat assert(si); - log_debug("Operating " PID_FMT " is now complete with code=%s status=%i", + log_debug("Operation " PID_FMT " is now complete with code=%s status=%i", o->pid, sigchld_code_to_string(si->si_code), si->si_status); diff --git a/src/network/netdev/vlan.c b/src/network/netdev/vlan.c index a3d961dac..5eb36ef68 100644 --- a/src/network/netdev/vlan.c +++ b/src/network/netdev/vlan.c @@ -144,6 +144,7 @@ int config_parse_vlan_qos_maps( for (const char *p = rvalue;;) { _cleanup_free_ struct ifla_vlan_qos_mapping *m = NULL; _cleanup_free_ char *w = NULL; + unsigned from, to; r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); if (r == -ENOMEM) @@ -155,20 +156,20 @@ int config_parse_vlan_qos_maps( if (r == 0) return 0; - m = new0(struct ifla_vlan_qos_mapping, 1); - if (!m) - return log_oom(); - - r = parse_range(w, &m->from, &m->to); + r = parse_range(w, &from, &to); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, w); continue; } - if (m->to > m->from || m->to == 0 || m->from == 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s, ignoring: %s", lvalue, w); - continue; - } + m = new(struct ifla_vlan_qos_mapping, 1); + if (!m) + return log_oom(); + + *m = (struct ifla_vlan_qos_mapping) { + .from = from, + .to = to, + }; r = set_ensure_consume(s, &vlan_qos_maps_hash_ops, TAKE_PTR(m)); if (r < 0) { diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 788c7957d..18d8fc31b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2144,7 +2144,7 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message) log_link_debug_errno(link, r, "Failed to manage link by its new hardware address, ignoring: %m"); } - r = ipv4ll_update_mac(link); + r = ipv4acd_update_mac(link); if (r < 0) return log_link_debug_errno(link, r, "Could not update MAC address in IPv4 ACD client: %m"); diff --git a/src/network/networkd-route-util.c b/src/network/networkd-route-util.c index 036638209..d461aadd6 100644 --- a/src/network/networkd-route-util.c +++ b/src/network/networkd-route-util.c @@ -3,6 +3,7 @@ #include #include "alloc-util.h" +#include "missing_threads.h" #include "networkd-address.h" #include "networkd-link.h" #include "networkd-manager.h" diff --git a/src/network/tc/tbf.c b/src/network/tc/tbf.c index d4344908d..647fc8cb1 100644 --- a/src/network/tc/tbf.c +++ b/src/network/tc/tbf.c @@ -304,13 +304,13 @@ static int token_bucket_filter_verify(QDisc *qdisc) { if (tbf->limit > 0 && tbf->latency > 0) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: Specifying both LimitSize= and LatencySec= is not allowed. " + "%s: Specifying both LimitBytes= and LatencySec= is not allowed. " "Ignoring [TokenBucketFilter] section from line %u.", qdisc->section->filename, qdisc->section->line); if (tbf->limit == 0 && tbf->latency == 0) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: Either LimitSize= or LatencySec= is required. " + "%s: Either LimitBytes= or LatencySec= is required. " "Ignoring [TokenBucketFilter] section from line %u.", qdisc->section->filename, qdisc->section->line); @@ -322,7 +322,7 @@ static int token_bucket_filter_verify(QDisc *qdisc) { if (tbf->burst == 0) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: Burst= is mandatory. " + "%s: BurstBytes= is mandatory. " "Ignoring [TokenBucketFilter] section from line %u.", qdisc->section->filename, qdisc->section->line); diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 3a2db101e..e38b319ef 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -224,8 +224,9 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void * log_link_warning_errno(l, r, "Failed to process RTNL link message, ignoring: %m"); r = link_update_monitor(l); - if (r < 0 && r != -ENODATA) - log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m"); + if (r < 0) + log_link_full_errno(l, IN_SET(r, -ENODATA, -ENOENT) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to update link state, ignoring: %m"); break; @@ -309,8 +310,9 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void * HASHMAP_FOREACH(l, m->links_by_index) { r = link_update_monitor(l); - if (r < 0 && r != -ENODATA) - log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m"); + if (r < 0) + log_link_full_errno(l, IN_SET(r, -ENODATA, -ENOENT) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to update link state, ignoring: %m"); } if (manager_configured(m)) diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index a54f1464b..63f59fe13 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -630,7 +630,7 @@ int mount_all(const char *dest, r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL); if (r < 0) - return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where); + return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].where); /* Skip this entry if it is not a remount. */ if (mount_table[k].what) { @@ -689,7 +689,7 @@ int mount_all(const char *dest, * for those. */ r = chase_symlinks(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL); if (r < 0) - return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].what); + return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].what); } r = mount_verbose_full( diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index 02142a935..c8ed3f1fd 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -605,7 +605,7 @@ static int oci_namespace_type(const char *name, JsonVariant *v, JsonDispatchFlag *nsflags = CLONE_NEWCGROUP; else return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), - "Unknown cgroup type, refusing: %s", n); + "Unknown namespace type, refusing: %s", n); return 0; } @@ -663,7 +663,7 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl if (!FLAGS_SET(n, CLONE_NEWNS)) return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP), - "Containers without file system namespace aren't supported."); + "Containers without a mount namespace aren't supported."); s->private_network = FLAGS_SET(n, CLONE_NEWNET); s->userns_mode = FLAGS_SET(n, CLONE_NEWUSER) ? USER_NAMESPACE_FIXED : USER_NAMESPACE_NO; @@ -819,7 +819,7 @@ static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFl return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE), "fileMode out of range, refusing."); - *mode = m; + *mode = (*mode & ~07777) | m; return 0; } @@ -874,7 +874,7 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags /* Suppress a couple of implicit device nodes */ r = devname_from_devnum(node->mode, makedev(node->major, node->minor), &path); if (r < 0) - json_log(e, flags|JSON_DEBUG, 0, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor); + json_log(e, flags|JSON_DEBUG, r, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor); else { if (PATH_IN_SET(path, "/dev/null", @@ -1589,7 +1589,7 @@ static int oci_sysctl(const char *name, JsonVariant *v, JsonDispatchFlags flags, assert_se(m = json_variant_string(w)); - if (sysctl_key_valid(k)) + if (!sysctl_key_valid(k)) return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "sysctl key invalid, refusing: %s", k); @@ -1829,6 +1829,7 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl { "names", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(struct syscall_rule, names), JSON_MANDATORY }, { "action", JSON_VARIANT_STRING, oci_seccomp_action, offsetof(struct syscall_rule, action), JSON_MANDATORY }, { "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 }, + {} }; struct syscall_rule rule = { .action = UINT32_MAX, @@ -2083,7 +2084,7 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f .timeout = USEC_INFINITY, }; - r = json_dispatch(e, table, oci_unexpected, flags, userdata); + r = json_dispatch(e, table, oci_unexpected, flags, new_item); if (r < 0) { free(new_item->path); strv_free(new_item->args); diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index e06de6807..08f22be1d 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -115,6 +115,8 @@ static void free_oci_hooks(OciHook *h, size_t n) { void device_node_array_free(DeviceNode *node, size_t n) { size_t i; + assert(node || n == 0); + for (i = 0; i < n; i++) free(node[i].path); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 6c978b6c8..7efb2ff80 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -812,6 +812,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:P", options, NULL)) >= 0) switch (c) { @@ -3540,6 +3543,7 @@ static int inner_child( * it again. Note that the other fds closed here are at least the locking and barrier fds. */ log_close(); log_set_open_when_needed(true); + log_settle_target(); (void) fdset_close_others(fds); @@ -4629,6 +4633,7 @@ static int merge_settings(Settings *settings, const char *path) { device_node_array_free(arg_extra_nodes, arg_n_extra_nodes); arg_extra_nodes = TAKE_PTR(settings->extra_nodes); arg_n_extra_nodes = settings->n_extra_nodes; + settings->n_extra_nodes = 0; return 0; } diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 75d749e73..1d6e25399 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -9,6 +9,7 @@ #include "fd-util.h" #include "log.h" #include "macro.h" +#include "missing_threads.h" #include "nss-systemd.h" #include "nss-util.h" #include "pthread-util.h" diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c index 4a43807b8..08a29ec77 100644 --- a/src/oom/oomd-manager.c +++ b/src/oom/oomd-manager.c @@ -516,7 +516,10 @@ static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t else clear_candidates = NULL; - r = oomd_kill_by_pgscan_rate(m->monitored_mem_pressure_cgroup_contexts_candidates, t->path, m->dry_run, &selected); + r = oomd_kill_by_pgscan_rate(m->monitored_mem_pressure_cgroup_contexts_candidates, + /* prefix= */ t->path, + /* dry_run= */ m->dry_run, + &selected); if (r == -ENOMEM) return log_oom(); if (r < 0) diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c index 24192f7b8..391d84605 100644 --- a/src/oom/oomd-util.c +++ b/src/oom/oomd-util.c @@ -315,7 +315,7 @@ int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run, char if (sorted[i]->pgscan == 0 && sorted[i]->current_memory_usage == 0) continue; - r = oomd_cgroup_kill(sorted[i]->path, true, dry_run); + r = oomd_cgroup_kill(sorted[i]->path, /* recurse= */ true, /* dry_run= */ dry_run); if (r == -ENOMEM) return r; /* Treat oom as a hard error */ if (r < 0) { @@ -359,7 +359,7 @@ int oomd_kill_by_swap_usage(Hashmap *h, uint64_t threshold_usage, bool dry_run, if (sorted[i]->swap_usage <= threshold_usage) continue; - r = oomd_cgroup_kill(sorted[i]->path, true, dry_run); + r = oomd_cgroup_kill(sorted[i]->path, /* recurse= */ true, /* dry_run= */ dry_run); if (r == -ENOMEM) return r; /* Treat oom as a hard error */ if (r < 0) { diff --git a/src/oom/oomd.c b/src/oom/oomd.c index 6cfe1a3f4..1ccbed1b9 100644 --- a/src/oom/oomd.c +++ b/src/oom/oomd.c @@ -44,7 +44,7 @@ static int help(void) { _cleanup_free_ char *link = NULL; int r; - r = terminal_urlify_man("systemd-oomd", "1", &link); + r = terminal_urlify_man("systemd-oomd", "8", &link); if (r < 0) return log_oom(); @@ -150,7 +150,7 @@ static int run(int argc, char *argv[]) { r = safe_atollu(swap, &s); if (r < 0 || s == 0) - log_warning("Swap is currently not detected; memory pressure usage will be degraded"); + log_warning("No swap; memory pressure usage will be degraded"); if (!is_pressure_supported()) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Pressure Stall Information (PSI) is not supported"); diff --git a/src/partition/repart.c b/src/partition/repart.c index 8f5c93c7c..2552167d7 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -1853,6 +1853,28 @@ static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) { return 0; } +static int context_open_and_lock_backing_fd(int *backing_fd, const char *node) { + _cleanup_close_ int fd = -EBADF; + + assert(backing_fd); + assert(node); + + if (*backing_fd >= 0) + return 0; + + fd = open(node, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(errno, "Failed to open device '%s': %m", node); + + /* Tell udev not to interfere while we are processing the device */ + if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0) + return log_error_errno(errno, "Failed to lock device '%s': %m", node); + + log_debug("Device %s opened and locked.", node); + *backing_fd = TAKE_FD(fd); + return 1; +} + static int context_load_partition_table( Context *context, const char *node, @@ -1915,13 +1937,9 @@ static int context_load_partition_table( if (*backing_fd < 0) { /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */ - *backing_fd = fd_reopen(fdisk_get_devfd(c), O_RDONLY|O_CLOEXEC); - if (*backing_fd < 0) - return log_error_errno(*backing_fd, "Failed to duplicate fdisk fd: %m"); - - /* Tell udev not to interfere while we are processing the device */ - if (flock(*backing_fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0) - return log_error_errno(errno, "Failed to lock block device: %m"); + r = context_open_and_lock_backing_fd(backing_fd, FORMAT_PROC_FD_PATH(fdisk_get_devfd(c))); + if (r < 0) + return r; } /* The offsets/sizes libfdisk returns to us will be in multiple of the sector size of the @@ -4945,7 +4963,7 @@ static int help(void) { _cleanup_free_ char *link = NULL; int r; - r = terminal_urlify_man("systemd-repart", "1", &link); + r = terminal_urlify_man("systemd-repart", "8", &link); if (r < 0) return log_oom(); @@ -5435,7 +5453,7 @@ static int acquire_root_devno( char **ret, int *ret_fd) { - _cleanup_free_ char *found_path = NULL; + _cleanup_free_ char *found_path = NULL, *node = NULL; dev_t devno, fd_devno = MODE_INVALID; _cleanup_close_ int fd = -1; struct stat st; @@ -5490,13 +5508,22 @@ static int acquire_root_devno( if (r < 0) log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p); - r = devname_from_devnum(S_IFBLK, devno, ret); + r = devname_from_devnum(S_IFBLK, devno, &node); if (r < 0) return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p); /* Only if we still look at the same block device we can reuse the fd. Otherwise return an * invalidated fd. */ - *ret_fd = fd_devno != MODE_INVALID && fd_devno == devno ? TAKE_FD(fd) : -1; + if (fd_devno != MODE_INVALID && fd_devno == devno) { + /* Tell udev not to interfere while we are processing the device */ + if (flock(fd, arg_dry_run ? LOCK_SH : LOCK_EX) < 0) + return log_error_errno(errno, "Failed to lock device '%s': %m", node); + + *ret_fd = TAKE_FD(fd); + } else + *ret_fd = -EBADF; + + *ret = TAKE_PTR(node); return 0; } diff --git a/src/portable/portabled-operation.c b/src/portable/portabled-operation.c index 26adb9091..6da73c6c1 100644 --- a/src/portable/portabled-operation.c +++ b/src/portable/portabled-operation.c @@ -14,7 +14,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat assert(si); - log_debug("Operating " PID_FMT " is now complete with code=%s status=%i", + log_debug("Operation " PID_FMT " is now complete with code=%s status=%i", o->pid, sigchld_code_to_string(si->si_code), si->si_status); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 505e3e7ba..e4d3e94c6 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -55,8 +55,8 @@ assert_cc(sizeof(DnsPacketHeader) == 12); /* RFC 1035 say 512 is the maximum, for classic unicast DNS */ #define DNS_PACKET_UNICAST_SIZE_MAX 512u -/* With EDNS0 we can use larger packets, default to 4096, which is what is commonly used */ -#define DNS_PACKET_UNICAST_SIZE_LARGE_MAX 4096u +/* With EDNS0 we can use larger packets, default to 1232, which is what is commonly used */ +#define DNS_PACKET_UNICAST_SIZE_LARGE_MAX 1232u struct DnsPacket { unsigned n_ref; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 5f890f950..a4379c192 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1222,8 +1222,10 @@ int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { return 0; r = dns_packet_append_rr(&packet, rr, 0, &start, &rds); - if (r < 0) + if (r < 0) { + dns_packet_unref(&packet); return r; + } assert(start == 0); assert(packet._data); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index f62efa87a..03abff4dc 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1705,9 +1705,9 @@ int socket_disable_pmtud(int fd, int af) { assert(fd >= 0); if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; + af = socket_get_family(fd); + if (af < 0) + return af; } switch (af) { diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c index d6cd184b5..c209abf64 100644 --- a/src/resolve/test-resolved-etc-hosts.c +++ b/src/resolve/test-resolved-etc-hosts.c @@ -40,7 +40,7 @@ TEST(parse_etc_hosts) { t[] = "/tmp/test-resolved-etc-hosts.XXXXXX"; int fd; - _cleanup_fclose_ FILE *f; + _cleanup_fclose_ FILE *f = NULL; fd = mkostemp_safe(t); assert_se(fd >= 0); @@ -125,7 +125,7 @@ TEST(parse_etc_hosts) { static void test_parse_file_one(const char *fname) { _cleanup_(etc_hosts_free) EtcHosts hosts = {}; - _cleanup_fclose_ FILE *f; + _cleanup_fclose_ FILE *f = NULL; log_info("/* %s(\"%s\") */", __func__, fname); diff --git a/src/run/run.c b/src/run/run.c index 627a6b11d..6734e2102 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -241,6 +241,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tPqGdSu:", options, NULL)) >= 0) switch (c) { diff --git a/src/shared/bpf-program.c b/src/shared/bpf-program.c index 31fa4448b..57a009a96 100644 --- a/src/shared/bpf-program.c +++ b/src/shared/bpf-program.c @@ -452,6 +452,9 @@ int bpf_program_deserialize_attachment(const char *v, FDSet *fds, BPFProgram **b return at; /* The rest is the path */ + if (isempty(v)) + return -EINVAL; + l = cunescape(v, 0, &unescaped); if (l < 0) return l; diff --git a/src/shared/bus-get-properties.c b/src/shared/bus-get-properties.c index 8b4f66b22..0a16c72d3 100644 --- a/src/shared/bus-get-properties.c +++ b/src/shared/bus-get-properties.c @@ -133,9 +133,9 @@ int bus_property_get_rlimit( s = is_soft ? strndupa_safe(property, is_soft - property) : property; /* Skip over any prefix, such as "Default" */ - assert_se(p = strstr(s, "Limit")); + assert_se(p = strstrafter(s, "Limit")); - z = rlimit_from_string(p + 5); + z = rlimit_from_string(p); assert(z >= 0); (void) getrlimit(z, &buf); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 922011ecc..766601235 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2720,7 +2720,7 @@ int unit_load_state(sd_bus *bus, const char *name, char **load_state) { if (!path) return log_oom(); - /* This function warns on it's own, because otherwise it'd be awkward to pass + /* This function warns on its own, because otherwise it'd be awkward to pass * the dbus error message around. */ r = sd_bus_get_property_string( diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c index 2ea83f05d..65be85101 100644 --- a/src/shared/cgroup-setup.c +++ b/src/shared/cgroup-setup.c @@ -8,6 +8,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "missing_threads.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c index a0b648bf7..7a4481683 100644 --- a/src/shared/coredump-util.c +++ b/src/shared/coredump-util.c @@ -3,6 +3,7 @@ #include "coredump-util.h" #include "extract-word.h" #include "fileio.h" +#include "stdio-util.h" #include "string-table.h" static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = { @@ -42,7 +43,7 @@ int coredump_filter_mask_from_string(const char *s, uint64_t *ret) { } if (streq(n, "all")) { - m = UINT64_MAX; + m = COREDUMP_FILTER_MASK_ALL; continue; } @@ -65,9 +66,9 @@ int coredump_filter_mask_from_string(const char *s, uint64_t *ret) { } int set_coredump_filter(uint64_t value) { - char t[STRLEN("0xFFFFFFFF")]; + char t[HEXADECIMAL_STR_MAX(uint64_t)]; - sprintf(t, "0x%"PRIx64, value); + xsprintf(t, "0x%"PRIx64, value); return write_string_file("/proc/self/coredump_filter", t, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER); diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h index 09e7ed443..f4d409813 100644 --- a/src/shared/coredump-util.h +++ b/src/shared/coredump-util.h @@ -22,6 +22,9 @@ typedef enum CoredumpFilter { 1u << COREDUMP_FILTER_ELF_HEADERS | \ 1u << COREDUMP_FILTER_PRIVATE_HUGE) +/* The kernel doesn't like UINT64_MAX and returns ERANGE, use UINT32_MAX to support future new flags */ +#define COREDUMP_FILTER_MASK_ALL UINT32_MAX + const char* coredump_filter_to_string(CoredumpFilter i) _const_; CoredumpFilter coredump_filter_from_string(const char *s) _pure_; int coredump_filter_mask_from_string(const char *s, uint64_t *ret); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 0f1b7281b..9bf128cc0 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -118,6 +118,21 @@ int probe_filesystem_full( if (!b) return -ENOMEM; + /* The Linux kernel maintains separate block device caches for main ("whole") and partition block + * devices, which means making a change to one might not be reflected immediately when reading via + * the other. That's massively confusing when mixing accesses to such devices. Let's address this in + * a limited way: when probing a file system that is not at the beginning of the block device we + * apparently probe a partition via the main block device, and in that case let's first flush the + * main block device cache, so that we get the data that the per-partition block device last + * sync'ed on. + * + * This only works under the assumption that any tools that write to the partition block devices + * issue an syncfs()/fsync() on the device after making changes. Typically file system formatting + * tools that write a superblock onto a partition block device do that, however. */ + if (offset != 0) + if (ioctl(fd, BLKFLSBUF, 0) < 0) + log_debug_errno(errno, "Failed to flush block device cache, ignoring: %m"); + errno = 0; r = blkid_probe_set_device( b, @@ -1335,6 +1350,7 @@ static int is_loop_device(const char *path) { static int run_fsck(int node_fd, const char *fstype) { int r, exit_status; pid_t pid; + _cleanup_free_ char *fsck_path = NULL; assert(node_fd >= 0); assert(fstype); @@ -1349,6 +1365,14 @@ static int run_fsck(int node_fd, const char *fstype) { return 0; } + r = find_executable("fsck", &fsck_path); + /* We proceed anyway if we can't determine whether the fsck + * binary for some specific fstype exists, + * but the lack of the main fsck binary should be considered + * an error. */ + if (r < 0) + return log_error_errno(r, "Cannot find fsck binary: %m"); + r = safe_fork_full( "(fsck)", &node_fd, 1, /* Leave the node fd open */ @@ -1358,7 +1382,7 @@ static int run_fsck(int node_fd, const char *fstype) { return log_debug_errno(r, "Failed to fork off fsck: %m"); if (r == 0) { /* Child */ - execl("/sbin/fsck", "/sbin/fsck", "-aT", FORMAT_PROC_FD_PATH(node_fd), NULL); + execl(fsck_path, fsck_path, "-aT", FORMAT_PROC_FD_PATH(node_fd), NULL); log_open(); log_debug_errno(errno, "Failed to execl() fsck: %m"); _exit(FSCK_OPERATIONAL_ERROR); @@ -1366,7 +1390,7 @@ static int run_fsck(int node_fd, const char *fstype) { exit_status = wait_for_terminate_and_check("fsck", pid, 0); if (exit_status < 0) - return log_debug_errno(exit_status, "Failed to fork off /sbin/fsck: %m"); + return log_debug_errno(exit_status, "Failed to fork off %s: %m", fsck_path); if ((exit_status & ~FSCK_ERROR_CORRECTED) != FSCK_SUCCESS) { log_debug("fsck failed with exit status %i.", exit_status); diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 19ddf0498..10f062d21 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -38,7 +38,7 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid, b pid_t _pid; int r; - if (null_or_empty_path(path)) { + if (null_or_empty_path(path) > 0) { log_debug("%s is empty (a mask).", path); return 0; } diff --git a/src/shared/fdset.c b/src/shared/fdset.c index 183fa239b..6f40c6aa0 100644 --- a/src/shared/fdset.c +++ b/src/shared/fdset.c @@ -74,6 +74,10 @@ int fdset_put(FDSet *s, int fd) { assert(s); assert(fd >= 0); + /* Avoid integer overflow in FD_TO_PTR() */ + if (fd == INT_MAX) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing invalid fd: %d", fd); + return set_put(MAKE_SET(s), FD_TO_PTR(fd)); } @@ -100,6 +104,12 @@ bool fdset_contains(FDSet *s, int fd) { assert(s); assert(fd >= 0); + /* Avoid integer overflow in FD_TO_PTR() */ + if (fd == INT_MAX) { + log_debug("Refusing invalid fd: %d", fd); + return false; + } + return !!set_get(MAKE_SET(s), FD_TO_PTR(fd)); } @@ -107,10 +117,16 @@ int fdset_remove(FDSet *s, int fd) { assert(s); assert(fd >= 0); + /* Avoid integer overflow in FD_TO_PTR() */ + if (fd == INT_MAX) + return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Refusing invalid fd: %d", fd); + return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT; } -int fdset_new_fill(FDSet **_s) { +int fdset_new_fill( + int filter_cloexec, /* if < 0 takes all fds, otherwise only those with O_CLOEXEC set (1) or unset (0) */ + FDSet **_s) { _cleanup_closedir_ DIR *d = NULL; int r = 0; FDSet *s; @@ -143,6 +159,20 @@ int fdset_new_fill(FDSet **_s) { if (fd == dirfd(d)) continue; + if (filter_cloexec >= 0) { + int fl; + + /* If user asked for that filter by O_CLOEXEC. This is useful so that fds that have + * been passed in can be collected and fds which have been created locally can be + * ignored, under the assumption that only the latter have O_CLOEXEC set. */ + fl = fcntl(fd, F_GETFD); + if (fl < 0) + return -errno; + + if (FLAGS_SET(fl, FD_CLOEXEC) != !!filter_cloexec) + continue; + } + r = fdset_put(s, fd); if (r < 0) goto finish; diff --git a/src/shared/fdset.h b/src/shared/fdset.h index 39d15ee4a..e8a6b4869 100644 --- a/src/shared/fdset.h +++ b/src/shared/fdset.h @@ -19,7 +19,7 @@ bool fdset_contains(FDSet *s, int fd); int fdset_remove(FDSet *s, int fd); int fdset_new_array(FDSet **ret, const int *fds, size_t n_fds); -int fdset_new_fill(FDSet **ret); +int fdset_new_fill(int filter_cloexec, FDSet **ret); int fdset_new_listen_fds(FDSet **ret, bool unset); int fdset_cloexec(FDSet *fds, bool b); diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index fa234c8b5..c0b0360f5 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -527,7 +527,7 @@ int find_esp_and_warn( flags | VERIFY_ESP_SEARCHING); if (r >= 0) goto found; - if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR)) /* This one is not it */ + if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL, -ENOTDIR, -ENOTTY)) /* This one is not it */ return r; p = mfree(p); diff --git a/src/shared/json.c b/src/shared/json.c index eda7bb195..e39c10449 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -1769,7 +1769,9 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) { if (!f) return -ENOMEM; - json_variant_dump(v, flags, f, NULL); + r = json_variant_dump(v, flags, f, NULL); + if (r < 0) + return r; /* Add terminating 0, so that the output buffer is a valid string. */ fputc('\0', f); @@ -2116,7 +2118,7 @@ int json_variant_strv(JsonVariant *v, char ***ret) { if (!json_variant_is_array(v)) return -EINVAL; - sensitive = v->sensitive; + sensitive = json_variant_is_sensitive(v); size_t n = json_variant_elements(v); l = new(char*, n+1); @@ -2127,7 +2129,7 @@ int json_variant_strv(JsonVariant *v, char ***ret) { JsonVariant *e; assert_se(e = json_variant_by_index(v, i)); - sensitive = sensitive || e->sensitive; + sensitive = sensitive || json_variant_is_sensitive(e); if (!json_variant_is_string(e)) { l[i] = NULL; diff --git a/src/shared/mkfs-util.c b/src/shared/mkfs-util.c index 8161dbf82..741a0da0a 100644 --- a/src/shared/mkfs-util.c +++ b/src/shared/mkfs-util.c @@ -184,6 +184,7 @@ int make_filesystem( "-I", "256", "-m", "0", "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1", + "-T", "default", node, NULL); else if (STR_IN_SET(fstype, "ext3", "ext4")) @@ -195,6 +196,7 @@ int make_filesystem( "-O", "has_journal", "-m", "0", "-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1", + "-T", "default", node, NULL); else if (streq(fstype, "btrfs")) { diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index 6742b7c75..eff13feb2 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -125,7 +125,7 @@ int umount_recursive(const char *prefix, int flags) { continue; } - log_debug("Successfully unmounted %s", path); + log_trace("Successfully unmounted %s", path); again = true; n++; @@ -397,7 +397,7 @@ int bind_remount_recursive_with_mountinfo( continue; } - log_debug("Remounted %s.", x); + log_trace("Remounted %s.", x); } } } diff --git a/src/shared/pam-util.c b/src/shared/pam-util.c index 9d74e08a2..bf576c482 100644 --- a/src/shared/pam-util.c +++ b/src/shared/pam-util.c @@ -53,15 +53,21 @@ static void cleanup_system_bus(pam_handle_t *handle, void *data, int error_statu sd_bus_flush_close_unref(data); } -int pam_acquire_bus_connection(pam_handle_t *handle, sd_bus **ret) { +int pam_acquire_bus_connection(pam_handle_t *handle, const char *module_name, sd_bus **ret) { _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_free_ char *cache_id = NULL; int r; assert(handle); + assert(module_name); assert(ret); + cache_id = strjoin("system-bus-", module_name); + if (!cache_id) + return pam_log_oom(handle); + /* We cache the bus connection so that we can share it between the session and the authentication hooks */ - r = pam_get_data(handle, "systemd-system-bus", (const void**) &bus); + r = pam_get_data(handle, cache_id, (const void**) &bus); if (r == PAM_SUCCESS && bus) { *ret = sd_bus_ref(TAKE_PTR(bus)); /* Increase the reference counter, so that the PAM data stays valid */ return PAM_SUCCESS; @@ -73,7 +79,7 @@ int pam_acquire_bus_connection(pam_handle_t *handle, sd_bus **ret) { if (r < 0) return pam_syslog_errno(handle, LOG_ERR, r, "Failed to connect to system bus: %m"); - r = pam_set_data(handle, "systemd-system-bus", bus, cleanup_system_bus); + r = pam_set_data(handle, cache_id, bus, cleanup_system_bus); if (r != PAM_SUCCESS) return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@"); @@ -83,10 +89,17 @@ int pam_acquire_bus_connection(pam_handle_t *handle, sd_bus **ret) { return PAM_SUCCESS; } -int pam_release_bus_connection(pam_handle_t *handle) { +int pam_release_bus_connection(pam_handle_t *handle, const char *module_name) { + _cleanup_free_ char *cache_id = NULL; int r; - r = pam_set_data(handle, "systemd-system-bus", NULL, NULL); + assert(module_name); + + cache_id = strjoin("system-bus-", module_name); + if (!cache_id) + return pam_log_oom(handle); + + r = pam_set_data(handle, cache_id, NULL, NULL); if (r != PAM_SUCCESS) return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to release PAM user record data: @PAMERR@"); diff --git a/src/shared/pam-util.h b/src/shared/pam-util.h index 1a17ea18c..d9c906aaa 100644 --- a/src/shared/pam-util.h +++ b/src/shared/pam-util.h @@ -24,7 +24,9 @@ static inline int pam_bus_log_parse_error(pam_handle_t *handle, int r) { return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse bus message: %m"); } -int pam_acquire_bus_connection(pam_handle_t *handle, sd_bus **ret); -int pam_release_bus_connection(pam_handle_t *handle); +/* Use a different module name per different PAM module. They are all loaded in the same namespace, and this + * helps avoid a clash in the internal data structures of sd-bus. It will be used as key for cache items. */ +int pam_acquire_bus_connection(pam_handle_t *handle, const char *module_name, sd_bus **ret); +int pam_release_bus_connection(pam_handle_t *handle, const char *module_name); void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status); diff --git a/src/shared/psi-util.c b/src/shared/psi-util.c index a3b553cb4..af8e278bd 100644 --- a/src/shared/psi-util.c +++ b/src/shared/psi-util.c @@ -8,6 +8,7 @@ #include "extract-word.h" #include "fd-util.h" #include "fileio.h" +#include "missing_threads.h" #include "parse-util.h" #include "psi-util.h" #include "string-util.h" diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index 6cc426573..4e5c53e3c 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -11,6 +11,7 @@ #include "cgroup-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "fs-util.h" #include "log.h" #include "macro.h" #include "mountpoint-util.h" @@ -28,9 +29,11 @@ static bool is_physical_fs(const struct statfs *sfs) { static int patch_dirfd_mode( int dfd, + bool refuse_already_set, mode_t *ret_old_mode) { struct stat st; + int r; assert(dfd >= 0); assert(ret_old_mode); @@ -39,16 +42,24 @@ static int patch_dirfd_mode( return -errno; if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - if (FLAGS_SET(st.st_mode, 0700)) /* Already set? */ - return -EACCES; /* original error */ + + if (FLAGS_SET(st.st_mode, 0700)) { /* Already set? */ + if (refuse_already_set) + return -EACCES; /* original error */ + + *ret_old_mode = st.st_mode; + return 0; + } + if (st.st_uid != geteuid()) /* this only works if the UID matches ours */ return -EACCES; - if (fchmod(dfd, (st.st_mode | 0700) & 07777) < 0) - return -errno; + r = fchmod_opath(dfd, (st.st_mode | 0700) & 07777); + if (r < 0) + return r; *ret_old_mode = st.st_mode; - return 0; + return 1; } int unlinkat_harder(int dfd, const char *filename, int unlink_flags, RemoveFlags remove_flags) { @@ -64,18 +75,18 @@ int unlinkat_harder(int dfd, const char *filename, int unlink_flags, RemoveFlags if (errno != EACCES || !FLAGS_SET(remove_flags, REMOVE_CHMOD)) return -errno; - r = patch_dirfd_mode(dfd, &old_mode); + r = patch_dirfd_mode(dfd, /* refuse_already_set = */ true, &old_mode); if (r < 0) return r; if (unlinkat(dfd, filename, unlink_flags) < 0) { r = -errno; /* Try to restore the original access mode if this didn't work */ - (void) fchmod(dfd, old_mode); + (void) fchmod(dfd, old_mode & 07777); return r; } - if (FLAGS_SET(remove_flags, REMOVE_CHMOD_RESTORE) && fchmod(dfd, old_mode) < 0) + if (FLAGS_SET(remove_flags, REMOVE_CHMOD_RESTORE) && fchmod(dfd, old_mode & 07777) < 0) return -errno; /* If this worked, we won't reset the old mode by default, since we'll need it for other entries too, @@ -99,22 +110,84 @@ int fstatat_harder(int dfd, if (errno != EACCES || !FLAGS_SET(remove_flags, REMOVE_CHMOD)) return -errno; - r = patch_dirfd_mode(dfd, &old_mode); + r = patch_dirfd_mode(dfd, /* refuse_already_set = */ true, &old_mode); if (r < 0) return r; if (fstatat(dfd, filename, ret, fstatat_flags) < 0) { r = -errno; - (void) fchmod(dfd, old_mode); + (void) fchmod(dfd, old_mode & 07777); return r; } - if (FLAGS_SET(remove_flags, REMOVE_CHMOD_RESTORE) && fchmod(dfd, old_mode) < 0) + if (FLAGS_SET(remove_flags, REMOVE_CHMOD_RESTORE) && fchmod(dfd, old_mode & 07777) < 0) return -errno; return 0; } +static int openat_harder(int dfd, const char *path, int open_flags, RemoveFlags remove_flags, mode_t *ret_old_mode) { + _cleanup_close_ int pfd = -EBADF, fd = -EBADF; + bool chmod_done = false; + mode_t old_mode; + int r; + + assert(dfd >= 0 || dfd == AT_FDCWD); + assert(path); + + /* Unlike unlink_harder() and fstatat_harder(), this chmod the specified path. */ + + if (FLAGS_SET(open_flags, O_PATH) || + !FLAGS_SET(open_flags, O_DIRECTORY) || + !FLAGS_SET(remove_flags, REMOVE_CHMOD)) { + + fd = RET_NERRNO(openat(dfd, path, open_flags)); + if (fd < 0) + return fd; + + if (ret_old_mode) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + *ret_old_mode = st.st_mode; + } + + return TAKE_FD(fd); + } + + pfd = RET_NERRNO(openat(dfd, path, (open_flags & (O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW)) | O_PATH)); + if (pfd < 0) + return pfd; + + if (FLAGS_SET(remove_flags, REMOVE_CHMOD)) { + r = patch_dirfd_mode(pfd, /* refuse_already_set = */ false, &old_mode); + if (r < 0) + return r; + + chmod_done = r; + } + + fd = fd_reopen(pfd, open_flags); + if (fd < 0) { + if (chmod_done) + (void) fchmod_opath(pfd, old_mode & 07777); + return fd; + } + + if (ret_old_mode) + *ret_old_mode = old_mode; + + return TAKE_FD(fd); +} + +static int rm_rf_children_impl( + int fd, + RemoveFlags flags, + const struct stat *root_dev, + mode_t old_mode); + static int rm_rf_inner_child( int fd, const char *fname, @@ -169,13 +242,16 @@ static int rm_rf_inner_child( if (!allow_recursion) return -EISDIR; - int subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + mode_t old_mode; + int subdir_fd = openat_harder(fd, fname, + O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, + flags, &old_mode); if (subdir_fd < 0) - return -errno; + return subdir_fd; /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type * again for each directory */ - q = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev); + q = rm_rf_children_impl(subdir_fd, flags | REMOVE_PHYSICAL, root_dev, old_mode); } else if (flags & REMOVE_ONLY_DIRECTORIES) return 0; @@ -191,6 +267,7 @@ static int rm_rf_inner_child( typedef struct TodoEntry { DIR *dir; /* A directory that we were operating on. */ char *dirname; /* The filename of that directory itself. */ + mode_t old_mode; /* The original file mode. */ } TodoEntry; static void free_todo_entries(TodoEntry **todos) { @@ -207,6 +284,22 @@ int rm_rf_children( RemoveFlags flags, const struct stat *root_dev) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return rm_rf_children_impl(fd, flags, root_dev, st.st_mode); +} + +static int rm_rf_children_impl( + int fd, + RemoveFlags flags, + const struct stat *root_dev, + mode_t old_mode) { + _cleanup_(free_todo_entries) TodoEntry *todos = NULL; size_t n_todo = 0; _cleanup_free_ char *dirname = NULL; /* Set when we are recursing and want to delete ourselves */ @@ -223,14 +316,20 @@ int rm_rf_children( * We need to remove the inner directory we were operating on. */ assert(dirname); r = unlinkat_harder(dirfd(todos[n_todo-1].dir), dirname, AT_REMOVEDIR, flags); - if (r < 0 && r != -ENOENT && ret == 0) - ret = r; + if (r < 0 && r != -ENOENT) { + if (ret == 0) + ret = r; + + if (FLAGS_SET(flags, REMOVE_CHMOD_RESTORE)) + (void) fchmodat(dirfd(todos[n_todo-1].dir), dirname, old_mode & 07777, 0); + } dirname = mfree(dirname); /* And now let's back out one level up */ n_todo --; d = TAKE_PTR(todos[n_todo].dir); dirname = TAKE_PTR(todos[n_todo].dirname); + old_mode = todos[n_todo].old_mode; assert(d); fd = dirfd(d); /* Retrieve the file descriptor from the DIR object */ @@ -287,17 +386,25 @@ int rm_rf_children( if (!newdirname) return log_oom(); - int newfd = openat(fd, de->d_name, - O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + mode_t mode; + int newfd = openat_harder(fd, de->d_name, + O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, + flags, &mode); if (newfd >= 0) { - todos[n_todo++] = (TodoEntry) { TAKE_PTR(d), TAKE_PTR(dirname) }; + todos[n_todo++] = (TodoEntry) { + .dir = TAKE_PTR(d), + .dirname = TAKE_PTR(dirname), + .old_mode = old_mode + }; + fd = newfd; dirname = TAKE_PTR(newdirname); + old_mode = mode; goto next_fd; - } else if (errno != -ENOENT && ret == 0) - ret = -errno; + } else if (newfd != -ENOENT && ret == 0) + ret = newfd; } else if (r < 0 && r != -ENOENT && ret == 0) ret = r; @@ -306,14 +413,20 @@ int rm_rf_children( if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(fd) < 0 && ret >= 0) ret = -errno; - if (n_todo == 0) + if (n_todo == 0) { + if (FLAGS_SET(flags, REMOVE_CHMOD_RESTORE) && + fchmod(fd, old_mode & 07777) < 0 && ret >= 0) + ret = -errno; + break; + } } return ret; } int rm_rf(const char *path, RemoveFlags flags) { + mode_t old_mode; int fd, r, q = 0; assert(path); @@ -345,10 +458,10 @@ int rm_rf(const char *path, RemoveFlags flags) { /* Not btrfs or not a subvolume */ } - fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + fd = openat_harder(AT_FDCWD, path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME, flags, &old_mode); if (fd >= 0) { /* We have a dir */ - r = rm_rf_children(fd, flags, NULL); + r = rm_rf_children_impl(fd, flags, NULL, old_mode); if (FLAGS_SET(flags, REMOVE_ROOT)) q = RET_NERRNO(rmdir(path)); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index dfac4da7c..d55900665 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -322,6 +322,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { "exit_group\0" "futex\0" "futex_time64\0" + "futex_waitv\0" "get_robust_list\0" "get_thread_area\0" "getegid\0" @@ -719,6 +720,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { "open_by_handle_at\0" "pivot_root\0" "quotactl\0" + "quotactl_fd\0" "setdomainname\0" "setfsuid\0" "setfsuid32\0" @@ -797,6 +799,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { "sched_setparam\0" "sched_setscheduler\0" "set_mempolicy\0" + "set_mempolicy_home_node\0" "setpriority\0" "setrlimit\0" }, @@ -1068,7 +1071,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter SECCOMP_FOREACH_LOCAL_ARCH(arch) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); r = seccomp_init_for_arch(&seccomp, arch, default_action); if (r < 0) @@ -1102,7 +1105,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; void *syscall_id, *val; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); r = seccomp_init_for_arch(&seccomp, arch, default_action); if (r < 0) @@ -1244,7 +1247,7 @@ int seccomp_restrict_namespaces(unsigned long retain) { SECCOMP_FOREACH_LOCAL_ARCH(arch) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW); if (r < 0) @@ -1296,7 +1299,7 @@ int seccomp_restrict_namespaces(unsigned long retain) { continue; } - log_debug("Blocking %s.", namespace_info[i].proc_name); + log_trace("Blocking %s.", namespace_info[i].proc_name); r = seccomp_rule_add_exact( seccomp, @@ -1362,7 +1365,7 @@ int seccomp_protect_sysctl(void) { SECCOMP_FOREACH_LOCAL_ARCH(arch) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); if (IN_SET(arch, SCMP_ARCH_AARCH64, @@ -1438,7 +1441,7 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; bool supported; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); switch (arch) { @@ -1622,7 +1625,7 @@ int seccomp_restrict_realtime_full(int error_code) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; int p; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW); if (r < 0) @@ -1714,7 +1717,7 @@ int seccomp_memory_deny_write_execute(void) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; int filter_syscall = 0, block_syscall = 0, shmat_syscall = 0, r; - log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch)); + log_trace("Operating on architecture: %s", seccomp_arch_to_string(arch)); switch (arch) { diff --git a/src/shared/securebits-util.h b/src/shared/securebits-util.h index f2e65cfcb..caf8e6d59 100644 --- a/src/shared/securebits-util.h +++ b/src/shared/securebits-util.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "missing_securebits.h" int secure_bits_to_string_alloc(int i, char **s); diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 7d9535345..bf671659d 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -347,11 +347,10 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { str += is_escaped; if (str[0] != '"') return -EINVAL; - str++; if (!is_escaped) { /* unescape double quotation '\"'->'"' */ - for (i = j = str; *i != '"'; i++, j++) { + for (j = str, i = str + 1; *i != '"'; i++, j++) { if (*i == '\0') return -EINVAL; if (i[0] == '\\' && i[1] == '"') @@ -359,12 +358,17 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { *j = *i; } j[0] = '\0'; + /* + * The return value must be terminated by two subsequent NULs + * so it could be safely interpreted as nulstr. + */ + j[1] = '\0'; } else { _cleanup_free_ char *unescaped = NULL; ssize_t l; /* find the end position of value */ - for (i = str; *i != '"'; i++) { + for (i = str + 1; *i != '"'; i++) { if (i[0] == '\\') i++; if (*i == '\0') @@ -372,12 +376,17 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { } i[0] = '\0'; - l = cunescape_length(str, i - str, 0, &unescaped); + l = cunescape_length(str + 1, i - (str + 1), 0, &unescaped); if (l < 0) return l; - assert(l <= i - str); + assert(l <= i - (str + 1)); memcpy(str, unescaped, l + 1); + /* + * The return value must be terminated by two subsequent NULs + * so it could be safely interpreted as nulstr. + */ + str[l + 1] = '\0'; } *ret_value = str; diff --git a/src/shared/uid-alloc-range.c b/src/shared/uid-alloc-range.c index dcecdbe34..195311942 100644 --- a/src/shared/uid-alloc-range.c +++ b/src/shared/uid-alloc-range.c @@ -3,6 +3,7 @@ #include "chase-symlinks.h" #include "fd-util.h" #include "fileio.h" +#include "missing_threads.h" #include "string-util.h" #include "uid-alloc-range.h" #include "user-util.h" diff --git a/src/shared/varlink.c b/src/shared/varlink.c index 4f7ac9768..6517b3fab 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -2638,7 +2638,9 @@ int varlink_server_deserialize_one(VarlinkServer *s, const char *value, FDSet *f r = safe_atoi(buf, &fd); if (r < 0) return log_debug_errno(r, "Unable to parse VarlinkServerSocket varlink-server-socket-fd=%s: %m", buf); - + if (fd < 0) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "VarlinkServerSocket varlink-server-socket-fd= has an invalid value: %d", fd); if (!fdset_contains(fds, fd)) return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "VarlinkServerSocket varlink-server-socket-fd= has unknown fd %d: %m", fd); diff --git a/src/shared/xml.c b/src/shared/xml.c index df381d85b..3b1fb41fe 100644 --- a/src/shared/xml.c +++ b/src/shared/xml.c @@ -87,26 +87,26 @@ int xml_tokenize(const char **p, char **name, void **state, unsigned *line) { if (startswith(b, "!--")) { /* A comment */ - e = strstr(b + 3, "-->"); + e = strstrafter(b + 3, "-->"); if (!e) return -EINVAL; - inc_lines(line, b, e + 3 - b); + inc_lines(line, b, e - b); - c = e + 3; + c = e; continue; } if (*b == '?') { /* Processing instruction */ - e = strstr(b + 1, "?>"); + e = strstrafter(b + 1, "?>"); if (!e) return -EINVAL; - inc_lines(line, b, e + 2 - b); + inc_lines(line, b, e - b); - c = e + 2; + c = e; continue; } diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index dcee0f900..f9c798a0b 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -74,6 +74,10 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 1); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; + /* "-" prevents getopt from permuting argv[] and moving the verb away * from argv[1]. Our interface to initrd promises it'll be there. */ while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0) diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 962c434a9..ca80ed4e9 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -39,6 +39,8 @@ #include "time-util.h" #include "util.h" +#define DEFAULT_HIBERNATE_DELAY_USEC_NO_BATTERY (2 * USEC_PER_HOUR) + static SleepOperation arg_operation = _SLEEP_OPERATION_INVALID; static int write_hibernate_location_info(const HibernateLocation *hibernate_location) { @@ -292,7 +294,8 @@ static int custom_timer_suspend(const SleepConfig *sleep_config) { if (hashmap_isempty(last_capacity)) /* In case of no battery, system suspend interval will be set to HibernateDelaySec= or 2 hours. */ - suspend_interval = timestamp_is_set(hibernate_timestamp) ? sleep_config->hibernate_delay_usec : DEFAULT_SUSPEND_ESTIMATION_USEC; + suspend_interval = timestamp_is_set(hibernate_timestamp) + ? sleep_config->hibernate_delay_usec : DEFAULT_HIBERNATE_DELAY_USEC_NO_BATTERY; else { r = get_total_suspend_interval(last_capacity, &suspend_interval); if (r < 0) { diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index c57293b0e..ed3fefe51 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -870,7 +870,7 @@ static int verb_help(int argc, char **argv, void *userdata) { _cleanup_free_ char *link = NULL; int r; - r = terminal_urlify_man("systemd-sysext", "1", &link); + r = terminal_urlify_man("systemd-sysext", "8", &link); if (r < 0) return log_oom(); diff --git a/src/systemctl/systemctl-list-dependencies.c b/src/systemctl/systemctl-list-dependencies.c index 86d1c5b7c..25ce09cbd 100644 --- a/src/systemctl/systemctl-list-dependencies.c +++ b/src/systemctl/systemctl-list-dependencies.c @@ -64,6 +64,7 @@ static int list_dependencies_one( _cleanup_strv_free_ char **deps = NULL; int r; + bool circular = false; assert(bus); assert(name); @@ -81,12 +82,7 @@ static int list_dependencies_one( STRV_FOREACH(c, deps) { if (strv_contains(*units, *c)) { - if (!arg_plain) { - printf(" "); - r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1); - if (r < 0) - return r; - } + circular = true; continue; } @@ -118,7 +114,7 @@ static int list_dependencies_one( printf("%s%s%s ", on, special_glyph(unit_active_state_to_glyph(active_state)), ansi_normal()); } - r = list_dependencies_print(*c, level, branches, c[1] == NULL); + r = list_dependencies_print(*c, level, branches, /* last = */ c[1] == NULL && !circular); if (r < 0) return r; @@ -129,6 +125,13 @@ static int list_dependencies_one( } } + if (circular && !arg_plain) { + printf(" "); + r = list_dependencies_print("...", level, branches, /* last = */ true); + if (r < 0) + return r; + } + if (!arg_plain) strv_remove(*units, name); diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c index 42a5b086c..6a50d1ca7 100644 --- a/src/systemctl/systemctl-start-unit.c +++ b/src/systemctl/systemctl-start-unit.c @@ -162,7 +162,14 @@ fail: if (arg_action != ACTION_SYSTEMCTL) return r; - log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r)); + if (sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) && + STR_IN_SET(method, "TryRestartUnit", "ReloadOrTryRestartUnit")) { + /* Ignore masked unit if try-* is requested */ + + log_debug_errno(r, "Failed to %s %s, ignoring: %s", job_type, name, bus_error_message(error, r)); + return 0; + } else + log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r)); if (!sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT, BUS_ERROR_UNIT_MASKED, @@ -359,7 +366,6 @@ int verb_start(int argc, char *argv[], void *userdata) { if (arg_marked) ret = enqueue_marked_jobs(bus, w); - else STRV_FOREACH(name, names) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/src/systemd/meson.build b/src/systemd/meson.build index efe1036ce..5a8760deb 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -59,6 +59,10 @@ if cc.has_argument('-std=iso9899:2017') opts += [['c', '-std=iso9899:2017']] endif +if cc.has_argument('-std=c2x') + opts += [['c', '-std=c2x']] +endif + if cxx_cmd != '' opts += [['c++'], ['c++', '-std=c++98'], @@ -72,6 +76,9 @@ if cxx_cmd != '' if cxx.has_argument('-std=c++20') opts += [['c++', '-std=c++20']] endif + if cxx.has_argument('-std=c++23') + opts += [['c++', '-std=c++23']] + endif endif foreach header : _systemd_headers + _not_installed_headers + [libudev_h_path] diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index 944ac41a4..7469f1636 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -1183,7 +1183,7 @@ static int verb_help(int argc, char **argv, void *userdata) { _cleanup_free_ char *link = NULL; int r; - r = terminal_urlify_man("systemd-sysupdate", "1", &link); + r = terminal_urlify_man("systemd-sysupdate", "8", &link); if (r < 0) return log_oom(); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 08b005e6b..7f45b70cb 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -402,7 +402,7 @@ static const char* pick_shell(const Item *i) { return NOLOGIN; } -static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) { +static int write_temporary_passwd(const char *passwd_path, FILE **ret_tmpfile, char **ret_tmpfile_path) { _cleanup_fclose_ FILE *original = NULL, *passwd = NULL; _cleanup_(unlink_and_freep) char *passwd_tmp = NULL; struct passwd *pw = NULL; @@ -498,7 +498,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char r = putpwent_sane(&n, passwd); if (r < 0) return log_debug_errno(r, "Failed to add new user \"%s\" to temporary passwd file: %m", - pw->pw_name); + i->name); } /* Append the remaining NIS entries if any */ @@ -519,8 +519,8 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char if (r < 0) return log_debug_errno(r, "Failed to flush %s: %m", passwd_tmp); - *tmpfile = TAKE_PTR(passwd); - *tmpfile_path = TAKE_PTR(passwd_tmp); + *ret_tmpfile = TAKE_PTR(passwd); + *ret_tmpfile_path = TAKE_PTR(passwd_tmp); return 0; } @@ -537,7 +537,7 @@ static usec_t epoch_or_now(void) { return now(CLOCK_REALTIME); } -static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char **tmpfile_path) { +static int write_temporary_shadow(const char *shadow_path, FILE **ret_tmpfile, char **ret_tmpfile_path) { _cleanup_fclose_ FILE *original = NULL, *shadow = NULL; _cleanup_(unlink_and_freep) char *shadow_tmp = NULL; struct spwd *sp = NULL; @@ -632,7 +632,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char r = putspent_sane(&n, shadow); if (r < 0) return log_debug_errno(r, "Failed to add new user \"%s\" to temporary shadow file: %m", - sp->sp_namp); + i->name); } /* Append the remaining NIS entries if any */ @@ -655,13 +655,13 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char if (r < 0) return log_debug_errno(r, "Failed to flush %s: %m", shadow_tmp); - *tmpfile = TAKE_PTR(shadow); - *tmpfile_path = TAKE_PTR(shadow_tmp); + *ret_tmpfile = TAKE_PTR(shadow); + *ret_tmpfile_path = TAKE_PTR(shadow_tmp); return 0; } -static int write_temporary_group(const char *group_path, FILE **tmpfile, char **tmpfile_path) { +static int write_temporary_group(const char *group_path, FILE **ret_tmpfile, char **ret_tmpfile_path) { _cleanup_fclose_ FILE *original = NULL, *group = NULL; _cleanup_(unlink_and_freep) char *group_tmp = NULL; bool group_changed = false; @@ -761,13 +761,13 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** return log_error_errno(r, "Failed to flush %s: %m", group_tmp); if (group_changed) { - *tmpfile = TAKE_PTR(group); - *tmpfile_path = TAKE_PTR(group_tmp); + *ret_tmpfile = TAKE_PTR(group); + *ret_tmpfile_path = TAKE_PTR(group_tmp); } return 0; } -static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, char **tmpfile_path) { +static int write_temporary_gshadow(const char * gshadow_path, FILE **ret_tmpfile, char **ret_tmpfile_path) { #if ENABLE_GSHADOW _cleanup_fclose_ FILE *original = NULL, *gshadow = NULL; _cleanup_(unlink_and_freep) char *gshadow_tmp = NULL; @@ -840,8 +840,8 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch return log_error_errno(r, "Failed to flush %s: %m", gshadow_tmp); if (group_changed) { - *tmpfile = TAKE_PTR(gshadow); - *tmpfile_path = TAKE_PTR(gshadow_tmp); + *ret_tmpfile = TAKE_PTR(gshadow); + *ret_tmpfile_path = TAKE_PTR(gshadow_tmp); } #endif return 0; @@ -878,23 +878,23 @@ static int write_files(void) { if (group) { r = make_backup("/etc/group", group_path); if (r < 0) - return log_error_errno(r, "Failed to make backup %s: %m", group_path); + return log_error_errno(r, "Failed to backup %s: %m", group_path); } if (gshadow) { r = make_backup("/etc/gshadow", gshadow_path); if (r < 0) - return log_error_errno(r, "Failed to make backup %s: %m", gshadow_path); + return log_error_errno(r, "Failed to backup %s: %m", gshadow_path); } if (passwd) { r = make_backup("/etc/passwd", passwd_path); if (r < 0) - return log_error_errno(r, "Failed to make backup %s: %m", passwd_path); + return log_error_errno(r, "Failed to backup %s: %m", passwd_path); } if (shadow) { r = make_backup("/etc/shadow", shadow_path); if (r < 0) - return log_error_errno(r, "Failed to make backup %s: %m", shadow_path); + return log_error_errno(r, "Failed to backup %s: %m", shadow_path); } /* And make the new files count */ diff --git a/src/test/test-bpf-devices.c b/src/test/test-bpf-devices.c index e17548373..0e1287eac 100644 --- a/src/test/test-bpf-devices.c +++ b/src/test/test-bpf-devices.c @@ -37,7 +37,7 @@ static void test_policy_closed(const char *cgroup_path, BPFProgram **installed_p "/dev/urandom", "/dev/tty", "/dev/ptmx") { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-"); @@ -74,7 +74,7 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p assert_se(r >= 0); { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/null"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -87,7 +87,7 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p } { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/random"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -100,7 +100,7 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p } { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/zero"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -113,7 +113,7 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p } { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/full"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -146,7 +146,7 @@ static void test_policy_allow_list_major(const char *pattern, const char *cgroup /* /dev/null, /dev/full have major==1, /dev/tty has major==5 */ { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/null"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -159,7 +159,7 @@ static void test_policy_allow_list_major(const char *pattern, const char *cgroup } { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/full"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -172,7 +172,7 @@ static void test_policy_allow_list_major(const char *pattern, const char *cgroup } { - _cleanup_close_ int fd, fd2; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; const char *s = "/dev/tty"; fd = open(s, O_CLOEXEC|O_RDONLY|O_NOCTTY); @@ -204,7 +204,7 @@ static void test_policy_allow_list_major_star(char type, const char *cgroup_path assert_se(r >= 0); { - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; const char *s = "/dev/null"; fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY); @@ -237,7 +237,7 @@ static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFP assert_se(r >= 0); { - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; const char *s = "/dev/null"; fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY); diff --git a/src/test/test-compress-benchmark.c b/src/test/test-compress-benchmark.c index 3f8225cbc..e14149fcd 100644 --- a/src/test/test-compress-benchmark.c +++ b/src/test/test-compress-benchmark.c @@ -78,7 +78,7 @@ static void test_compress_decompress(const char* label, const char* type, usec_t n, n2 = 0; float dt; - _cleanup_free_ char *text, *buf; + _cleanup_free_ char *text = NULL, *buf = NULL; _cleanup_free_ void *buf2 = NULL; size_t skipped = 0, compressed = 0, total = 0; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 4091b425d..3509f51cb 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -160,7 +160,7 @@ TEST(copy_tree) { (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); STRV_FOREACH(p, files) { - _cleanup_free_ char *f, *c; + _cleanup_free_ char *f = NULL, *c = NULL; int k; assert_se(f = path_join(original_dir, *p)); @@ -175,7 +175,7 @@ TEST(copy_tree) { } STRV_FOREACH_PAIR(ll, p, symlinks) { - _cleanup_free_ char *f, *l; + _cleanup_free_ char *f = NULL, *l = NULL; assert_se(f = path_join(original_dir, *p)); assert_se(l = path_join(original_dir, *ll)); @@ -185,7 +185,7 @@ TEST(copy_tree) { } STRV_FOREACH_PAIR(ll, p, hardlinks) { - _cleanup_free_ char *f, *l; + _cleanup_free_ char *f = NULL, *l = NULL; assert_se(f = path_join(original_dir, *p)); assert_se(l = path_join(original_dir, *ll)); @@ -200,7 +200,7 @@ TEST(copy_tree) { assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS) == 0); STRV_FOREACH(p, files) { - _cleanup_free_ char *buf, *f, *c = NULL; + _cleanup_free_ char *buf = NULL, *f = NULL, *c = NULL; size_t sz; int k; @@ -222,7 +222,7 @@ TEST(copy_tree) { } STRV_FOREACH_PAIR(ll, p, symlinks) { - _cleanup_free_ char *target, *f, *l; + _cleanup_free_ char *target = NULL, *f = NULL, *l = NULL; assert_se(f = strjoin(original_dir, *p)); assert_se(l = strjoin(copy_dir, *ll)); @@ -232,7 +232,7 @@ TEST(copy_tree) { } STRV_FOREACH_PAIR(ll, p, hardlinks) { - _cleanup_free_ char *f, *l; + _cleanup_free_ char *f = NULL, *l = NULL; struct stat a, b; assert_se(f = strjoin(copy_dir, *p)); diff --git a/src/test/test-coredump-util.c b/src/test/test-coredump-util.c index 40b68df9f..87dc371a8 100644 --- a/src/test/test-coredump-util.c +++ b/src/test/test-coredump-util.c @@ -23,6 +23,8 @@ TEST(coredump_filter_mask_from_string) { uint64_t f; assert_se(coredump_filter_mask_from_string("default", &f) == 0); assert_se(f == COREDUMP_FILTER_MASK_DEFAULT); + assert_se(coredump_filter_mask_from_string("all", &f) == 0); + assert_se(f == COREDUMP_FILTER_MASK_ALL); assert_se(coredump_filter_mask_from_string(" default\tdefault\tdefault ", &f) == 0); assert_se(f == COREDUMP_FILTER_MASK_DEFAULT); diff --git a/src/test/test-date.c b/src/test/test-date.c index 097066b61..930f1bd7d 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -46,7 +46,7 @@ static void test_should_fail(const char *p) { } static void test_one(const char *p) { - _cleanup_free_ char *with_utc; + _cleanup_free_ char *with_utc = NULL; with_utc = strjoin(p, " UTC"); test_should_pass(p); @@ -54,7 +54,7 @@ static void test_one(const char *p) { } static void test_one_noutc(const char *p) { - _cleanup_free_ char *with_utc; + _cleanup_free_ char *with_utc = NULL; with_utc = strjoin(p, " UTC"); test_should_pass(p); diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index 731719336..4bb5dfc09 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -76,7 +76,7 @@ TEST(ellipsize_mem) { } static void test_ellipsize_one(const char *p) { - _cleanup_free_ char *t; + _cleanup_free_ char *t = NULL; t = ellipsize(p, columns(), 70); puts(t); free(t); diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c index 461a0f081..c8ec0e227 100644 --- a/src/test/test-env-file.c +++ b/src/test/test-env-file.c @@ -58,7 +58,6 @@ "d= \" \\n\\t\\$\\`\\\\\n" \ "\" \n" - TEST(load_env_file_1) { _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; assert_se(write_tmpfile(name, env_file_1) == 0); @@ -129,6 +128,25 @@ TEST(load_env_file_6) { assert_se(data[4] == NULL); } +TEST(load_env_file_invalid_utf8) { + /* Test out a couple of assignments where the key/value has an invalid + * UTF-8 character ("noncharacter") + * + * See: https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Non-characters + */ + FOREACH_STRING(s, + "fo\ufffeo=bar", + "foo=b\uffffar", + "baz=hello world\ufffe") { + _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX"; + assert_se(write_tmpfile(name, s) == 0); + + _cleanup_strv_free_ char **data = NULL; + assert_se(load_env_file(NULL, name, &data) == -EINVAL); + assert_se(!data); + } +} + TEST(write_and_load_env_file) { /* Make sure that our writer, parser and the shell agree on what our env var files mean */ diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index cc37d9632..144d40f9b 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -453,4 +453,48 @@ TEST(getenv_steal_erase) { assert_se(r > 0); } +TEST(strv_env_name_is_valid) { + const char *valid_env_names[] = {"HOME", "USER", "SHELL", "PATH", NULL}; + const char *invalid_env_names[] = {"", "PATH", "home", "user", "SHELL", NULL}; + const char *repeated_env_names[] = {"HOME", "USER", "SHELL", "USER", NULL}; + assert_se(strv_env_name_is_valid((char **) valid_env_names)); + assert_se(!strv_env_name_is_valid((char **) invalid_env_names)); + assert_se(!strv_env_name_is_valid((char **) repeated_env_names)); +} + +TEST(getenv_path_list) { + _cleanup_strv_free_ char **path_list = NULL; + + /* Empty paths */ + FOREACH_STRING(s, "", ":", ":::::", " : ::: :: :") { + assert_se(setenv("TEST_GETENV_PATH_LIST", s, 1) >= 0); + assert_se(getenv_path_list("TEST_GETENV_PATH_LIST", &path_list) == -EINVAL); + assert_se(!path_list); + } + + /* Invalid paths */ + FOREACH_STRING(s, ".", "..", "/../", "/", "/foo/bar/baz/../foo", "foo/bar/baz") { + assert_se(setenv("TEST_GETENV_PATH_LIST", s, 1) >= 0); + assert_se(getenv_path_list("TEST_GETENV_PATH_LIST", &path_list) == -EINVAL); + assert_se(!path_list); + } + + /* Valid paths mixed with invalid ones */ + assert_se(setenv("TEST_GETENV_PATH_LIST", "/foo:/bar/baz:/../:/hello", 1) >= 0); + assert_se(getenv_path_list("TEST_GETENV_PATH_LIST", &path_list) == -EINVAL); + assert_se(!path_list); + + /* Finally some valid paths */ + assert_se(setenv("TEST_GETENV_PATH_LIST", "/foo:/bar/baz:/hello/world:/path with spaces:/final", 1) >= 0); + assert_se(getenv_path_list("TEST_GETENV_PATH_LIST", &path_list) >= 0); + assert_se(streq(path_list[0], "/foo")); + assert_se(streq(path_list[1], "/bar/baz")); + assert_se(streq(path_list[2], "/hello/world")); + assert_se(streq(path_list[3], "/path with spaces")); + assert_se(streq(path_list[4], "/final")); + assert_se(path_list[5] == NULL); + + assert_se(unsetenv("TEST_GETENV_PATH_LIST") >= 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-escape.c b/src/test/test-escape.c index b9e984cb9..afc523fd2 100644 --- a/src/test/test-escape.c +++ b/src/test/test-escape.c @@ -6,14 +6,14 @@ #include "tests.h" TEST(cescape) { - _cleanup_free_ char *t; + _cleanup_free_ char *t = NULL; assert_se(t = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); assert_se(streq(t, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); } TEST(xescape) { - _cleanup_free_ char *t; + _cleanup_free_ char *t = NULL; assert_se(t = xescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", "")); assert_se(streq(t, "abc\\x5c\"\\x08\\x0c\\x0a\\x0d\\x09\\x0b\\x07\\x03\\x7f\\x9c\\xcb")); @@ -29,7 +29,7 @@ static void test_xescape_full_one(bool eight_bits) { log_info("/* %s */", __func__); for (unsigned i = 0; i < 60; i++) { - _cleanup_free_ char *t, *q; + _cleanup_free_ char *t = NULL, *q = NULL; assert_se(t = xescape_full("abc\\\"\b\f\n\r\t\v\a\003\177\234\313", "b", i, flags)); @@ -65,7 +65,7 @@ TEST(test_xescape_full) { } TEST(cunescape) { - _cleanup_free_ char *unescaped; + _cleanup_free_ char *unescaped = NULL; assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); @@ -132,7 +132,7 @@ TEST(cunescape) { } static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { - _cleanup_free_ char *r; + _cleanup_free_ char *r = NULL; assert_se(r = shell_escape(s, bad)); log_debug("%s โ†’ %s (expected %s)", s, r, expected); @@ -203,7 +203,7 @@ TEST(shell_maybe_quote) { } static void test_quote_command_line_one(char **argv, const char *expected) { - _cleanup_free_ char *s; + _cleanup_free_ char *s = NULL; assert_se(s = quote_command_line(argv, SHELL_ESCAPE_EMPTY)); log_info("%s", s); @@ -224,7 +224,7 @@ TEST(quote_command_line) { } static void test_octescape_one(const char *s, const char *expected) { - _cleanup_free_ char *ret; + _cleanup_free_ char *ret = NULL; assert_se(ret = octescape(s, strlen_ptr(s))); log_debug("octescape(\"%s\") โ†’ \"%s\" (expected: \"%s\")", strnull(s), ret, expected); diff --git a/src/test/test-execve.c b/src/test/test-execve.c index 38adc728a..e7a9a5137 100644 --- a/src/test/test-execve.c +++ b/src/test/test-execve.c @@ -20,7 +20,7 @@ */ static int run(int argc, char **argv) { - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; char **args = strv_skip(argv, 1); int r; diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index 5b5a71246..fa43f836c 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -274,6 +274,7 @@ static void test_close_all_fds_inner(void) { /* Close logging fd first, so that we don't confuse it by closing its fd */ log_close(); log_set_open_when_needed(true); + log_settle_target(); /* Close all but the ones to keep */ assert_se(close_all_fds(keep, n_keep) >= 0); diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c index 5d63eeee3..e2ef86343 100644 --- a/src/test/test-fdset.c +++ b/src/test/test-fdset.c @@ -13,14 +13,48 @@ TEST(fdset_new_fill) { int fd = -1; _cleanup_fdset_free_ FDSet *fdset = NULL; - char name[] = "/tmp/test-fdset_new_fill.XXXXXX"; - fd = mkostemp_safe(name); + log_close(); + log_set_open_when_needed(true); + + fd = open("/dev/null", O_CLOEXEC|O_RDONLY); assert_se(fd >= 0); - assert_se(fdset_new_fill(&fdset) >= 0); - assert_se(fdset_contains(fdset, fd)); - unlink(name); + assert_se(fdset_new_fill(/* filter_cloexec= */ -1, &fdset) >= 0); + assert_se(fdset_contains(fdset, fd)); + fdset = fdset_free(fdset); + assert_se(fcntl(fd, F_GETFD) < 0); + assert_se(errno == EBADF); + + fd = open("/dev/null", O_CLOEXEC|O_RDONLY); + assert_se(fd >= 0); + + assert_se(fdset_new_fill(/* filter_cloexec= */ 0, &fdset) >= 0); + assert_se(!fdset_contains(fdset, fd)); + fdset = fdset_free(fdset); + assert_se(fcntl(fd, F_GETFD) >= 0); + + assert_se(fdset_new_fill(/* filter_cloexec= */ 1, &fdset) >= 0); + assert_se(fdset_contains(fdset, fd)); + fdset = fdset_free(fdset); + assert_se(fcntl(fd, F_GETFD) < 0); + assert_se(errno == EBADF); + + fd = open("/dev/null", O_RDONLY); + assert_se(fd >= 0); + + assert_se(fdset_new_fill(/* filter_cloexec= */ 1, &fdset) >= 0); + assert_se(!fdset_contains(fdset, fd)); + fdset = fdset_free(fdset); + assert_se(fcntl(fd, F_GETFD) >= 0); + + assert_se(fdset_new_fill(/* filter_cloexec= */ 0, &fdset) >= 0); + assert_se(fdset_contains(fdset, fd)); + fdset = fdset_free(fdset); + assert_se(fcntl(fd, F_GETFD) < 0); + assert_se(errno == EBADF); + + log_open(); } TEST(fdset_put_dup) { diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index ba6dd9ace..bc062d4cc 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -428,7 +428,7 @@ TEST(write_string_stream) { TEST(write_string_file) { _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file-XXXXXX"; char buf[64] = {}; - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; fd = mkostemp_safe(fn); assert_se(fd >= 0); @@ -441,7 +441,7 @@ TEST(write_string_file) { TEST(write_string_file_no_create) { _cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX"; - _cleanup_close_ int fd; + _cleanup_close_ int fd = -EBADF; char buf[64] = {}; fd = mkostemp_safe(fn); diff --git a/src/test/test-json.c b/src/test/test-json.c index 946c827cc..563741dd3 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -19,7 +19,7 @@ static void test_tokenizer_one(const char *data, ...) { void *state = NULL; va_list ap; - _cleanup_free_ char *cdata; + _cleanup_free_ char *cdata = NULL; assert_se(cdata = cescape(data)); log_info("/* %s data=\"%s\" */", __func__, cdata); diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c index defecd3a5..7758f0adc 100644 --- a/src/test/test-nss-hosts.c +++ b/src/test/test-nss-hosts.c @@ -367,7 +367,9 @@ static int make_addresses(struct local_address **addresses) { .address.in = { htobe32(0x7F000002) } }; addrs[n++] = (struct local_address) { .family = AF_INET6, .address.in6 = in6addr_loopback }; - return 0; + + *addresses = TAKE_PTR(addrs); + return n; } static int test_one_module(const char *dir, @@ -447,7 +449,7 @@ static int parse_argv(int argc, char **argv, } } } else { - _cleanup_free_ char *hostname; + _cleanup_free_ char *hostname = NULL; assert_se(hostname = gethostname_malloc()); assert_se(names = strv_new("localhost", "_gateway", "_outbound", "foo_no_such_host", hostname)); diff --git a/src/test/test-rm-rf.c b/src/test/test-rm-rf.c index 1eb9a4907..6a8b7d823 100644 --- a/src/test/test-rm-rf.c +++ b/src/test/test-rm-rf.c @@ -10,31 +10,79 @@ #include "tmpfile-util.h" static void test_rm_rf_chmod_inner(void) { - _cleanup_free_ char *d = NULL; - const char *x, *y; + _cleanup_(rm_rf_physical_and_freep) char *d = NULL; + const char *a, *b, *x, *y; + struct stat st; assert_se(getuid() != 0); - assert_se(mkdtemp_malloc(NULL, &d) >= 0); + assert_se(mkdtemp_malloc("/tmp/test-rm-rf.XXXXXXX", &d) >= 0); + a = strjoina(d, "/a"); + b = strjoina(a, "/b"); + x = strjoina(d, "/x"); + y = strjoina(x, "/y"); - x = strjoina(d, "/d"); assert_se(mkdir(x, 0700) >= 0); - y = strjoina(x, "/f"); assert_se(mknod(y, S_IFREG | 0600, 0) >= 0); assert_se(chmod(y, 0400) >= 0); assert_se(chmod(x, 0500) >= 0); assert_se(chmod(d, 0500) >= 0); - assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_ROOT) == -EACCES); + assert_se(rm_rf(d, REMOVE_PHYSICAL) == -EACCES); assert_se(access(d, F_OK) >= 0); assert_se(access(x, F_OK) >= 0); assert_se(access(y, F_OK) >= 0); - assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_ROOT|REMOVE_CHMOD) >= 0); + assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_CHMOD) >= 0); + + assert_se(access(d, F_OK) >= 0); + assert_se(access(x, F_OK) < 0 && errno == ENOENT); + assert_se(access(y, F_OK) < 0 && errno == ENOENT); + + assert_se(mkdir(a, 0700) >= 0); + assert_se(mkdir(b, 0700) >= 0); + assert_se(mkdir(x, 0700) >= 0); + assert_se(mknod(y, S_IFREG | 0600, 0) >= 0); + + assert_se(chmod(b, 0000) >= 0); + assert_se(chmod(a, 0000) >= 0); + assert_se(chmod(y, 0000) >= 0); + assert_se(chmod(x, 0000) >= 0); + assert_se(chmod(d, 0500) >= 0); + + assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_CHMOD|REMOVE_CHMOD_RESTORE|REMOVE_ONLY_DIRECTORIES) == -ENOTEMPTY); + + assert_se(access(a, F_OK) < 0 && errno == ENOENT); + assert_se(access(d, F_OK) >= 0); + assert_se(stat(d, &st) >= 0 && (st.st_mode & 07777) == 0500); + assert_se(access(x, F_OK) >= 0); + assert_se(stat(x, &st) >= 0 && (st.st_mode & 07777) == 0000); + assert_se(chmod(x, 0700) >= 0); + assert_se(access(y, F_OK) >= 0); + assert_se(stat(y, &st) >= 0 && (st.st_mode & 07777) == 0000); + + assert_se(chmod(y, 0000) >= 0); + assert_se(chmod(x, 0000) >= 0); + assert_se(chmod(d, 0000) >= 0); + + assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_CHMOD|REMOVE_CHMOD_RESTORE) >= 0); + + assert_se(stat(d, &st) >= 0 && (st.st_mode & 07777) == 0000); + assert_se(access(d, F_OK) >= 0); + assert_se(chmod(d, 0700) >= 0); + assert_se(access(x, F_OK) < 0 && errno == ENOENT); + + assert_se(mkdir(x, 0700) >= 0); + assert_se(mknod(y, S_IFREG | 0600, 0) >= 0); + + assert_se(chmod(y, 0000) >= 0); + assert_se(chmod(x, 0000) >= 0); + assert_se(chmod(d, 0000) >= 0); + + assert_se(rm_rf(d, REMOVE_PHYSICAL|REMOVE_CHMOD|REMOVE_ROOT) >= 0); - errno = 0; assert_se(access(d, F_OK) < 0 && errno == ENOENT); } diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index 799e93dce..c45fc2474 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -22,7 +22,7 @@ TEST(parse_sleep_config) { assert_se(parse_sleep_config(&sleep_config) == 0); - _cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys; + _cleanup_free_ char *sum = NULL, *sus = NULL, *him = NULL, *his = NULL, *hym = NULL, *hys = NULL; sum = strv_join(sleep_config->modes[SLEEP_SUSPEND], ", "); sus = strv_join(sleep_config->states[SLEEP_SUSPEND], ", "); diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index 4a8ff4bd1..f5c491b9c 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "sd-id128.h" + #include "alloc-util.h" #include "log.h" #include "specifier.h" @@ -144,6 +146,31 @@ TEST(specifiers) { } } +/* Bunch of specifiers that are not part of the common lists */ +TEST(specifiers_assorted) { + const sd_id128_t id = SD_ID128_ALLF; + const uint64_t llu = UINT64_MAX; + const Specifier table[] = { + /* Used in src/partition/repart.c */ + { 'a', specifier_uuid, &id }, + { 'b', specifier_uint64, &llu }, + {} + }; + + for (const Specifier *s = table; s->specifier; s++) { + char spec[3]; + _cleanup_free_ char *resolved = NULL; + int r; + + xsprintf(spec, "%%%c", s->specifier); + + r = specifier_printf(spec, SIZE_MAX, table, NULL, NULL, &resolved); + assert_se(r >= 0); + + log_info("%%%c โ†’ %s", s->specifier, resolved); + } +} + TEST(specifiers_missing_data_ok) { _cleanup_free_ char *resolved = NULL; diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 9233c63f9..70bd59b2b 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -13,8 +13,8 @@ static ssize_t add_string(struct strbuf *sb, const char *s) { } TEST(strbuf) { - _cleanup_(strbuf_freep) struct strbuf *sb; - _cleanup_strv_free_ char **l; + _cleanup_(strbuf_freep) struct strbuf *sb = NULL; + _cleanup_strv_free_ char **l = NULL; ssize_t a, b, c, d, e, f, g, h; sb = strbuf_new(); diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index d0a227279..c28263e2c 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -260,7 +260,7 @@ TEST(strextend_with_separator) { } TEST(strrep) { - _cleanup_free_ char *one, *three, *zero; + _cleanup_free_ char *one = NULL, *three = NULL, *zero = NULL; one = strrep("waldo", 1); three = strrep("waldo", 3); zero = strrep("waldo", 0); @@ -1169,4 +1169,21 @@ TEST(streq_skip_trailing_chars) { assert_se(!streq_skip_trailing_chars("", "f", NULL)); } +TEST(strstrafter) { + static const char buffer[] = "abcdefghijklmnopqrstuvwxyz"; + + assert_se(!strstrafter(NULL, NULL)); + assert_se(!strstrafter("", NULL)); + assert_se(!strstrafter(NULL, "")); + assert_se(streq_ptr(strstrafter("", ""), "")); + + assert_se(strstrafter(buffer, "a") == buffer + 1); + assert_se(strstrafter(buffer, "") == buffer); + assert_se(strstrafter(buffer, "ab") == buffer + 2); + assert_se(strstrafter(buffer, "cde") == buffer + 5); + assert_se(strstrafter(buffer, "xyz") == strchr(buffer, 0)); + assert_se(strstrafter(buffer, buffer) == strchr(buffer, 0)); + assert_se(!strstrafter(buffer, "-")); +} + DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index b892396f0..1ef019b18 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -201,8 +201,8 @@ TEST(strv_join_full) { } static void test_strv_unquote_one(const char *quoted, char **list) { - _cleanup_strv_free_ char **s; - _cleanup_free_ char *j; + _cleanup_strv_free_ char **s = NULL; + _cleanup_free_ char *j = NULL; unsigned i = 0; int r; diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 6b546fb9f..615945f5f 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -240,7 +240,7 @@ TEST(format_timespan) { test_format_timespan_accuracy(USEC_PER_SEC); /* See issue #23928. */ - _cleanup_free_ char *buf; + _cleanup_free_ char *buf = NULL; assert_se(buf = new(char, 5)); assert_se(buf == format_timespan(buf, 5, 100005, 1000)); } diff --git a/src/test/test-udev-util.c b/src/test/test-udev-util.c index 1db2dad4f..4be3694e9 100644 --- a/src/test/test-udev-util.c +++ b/src/test/test-udev-util.c @@ -24,6 +24,11 @@ static void test_udev_rule_parse_value_one(const char *in, const char *expected_ } else { assert_se(streq_ptr(value, expected_value)); assert_se(endpos == str + strlen(in)); + /* + * The return value must be terminated by two subsequent NULs + * so it could be safely interpreted as nulstr. + */ + assert_se(value[strlen(value) + 1] == '\0'); } } diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index eec4831b4..fe9f6e5c4 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -582,7 +582,7 @@ TEST(unit_name_to_instance) { } TEST(unit_name_escape) { - _cleanup_free_ char *r; + _cleanup_free_ char *r = NULL; r = unit_name_escape("ab+-c.a/bc@foo.service"); assert_se(r); diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index f070c171f..965d1e96f 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -100,7 +100,7 @@ TEST(utf8_encoded_valid_unichar) { } TEST(utf8_escape_invalid) { - _cleanup_free_ char *p1, *p2, *p3; + _cleanup_free_ char *p1 = NULL, *p2 = NULL, *p3 = NULL; p1 = utf8_escape_invalid("goo goo goo"); log_debug("\"%s\"", p1); @@ -116,7 +116,7 @@ TEST(utf8_escape_invalid) { } TEST(utf8_escape_non_printable) { - _cleanup_free_ char *p1, *p2, *p3, *p4, *p5, *p6; + _cleanup_free_ char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL, *p5 = NULL, *p6 = NULL; p1 = utf8_escape_non_printable("goo goo goo"); log_debug("\"%s\"", p1); @@ -149,7 +149,7 @@ TEST(utf8_escape_non_printable_full) { "\001 \019\20\a", /* control characters */ "\xef\xbf\x30\x13") /* misplaced continuation bytes followed by a digit and cc */ for (size_t cw = 0; cw < 22; cw++) { - _cleanup_free_ char *p, *q; + _cleanup_free_ char *p = NULL, *q = NULL; size_t ew; p = utf8_escape_non_printable_full(s, cw, false); diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index ea1872d0c..6f23973b9 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -972,10 +972,10 @@ static int manager_network_read_link_servers(Manager *m) { assert(m); r = sd_network_get_ntp(&ntp); - if (r < 0) { + if (r < 0 && r != -ENODATA) { if (r == -ENOMEM) log_oom(); - else if (r != -ENODATA) + else log_debug_errno(r, "Failed to get link NTP servers: %m"); goto clear; } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index ba69a190d..b18ac7538 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2283,7 +2283,7 @@ static int rm_if_wrong_type_safe( return 0; (void) fd_get_path(parent_fd, &parent_name); - log_notice("Wrong file type 0x%x; rm -rf \"%s/%s\"", st.st_mode & S_IFMT, strna(parent_name), name); + log_notice("Wrong file type 0o%o; rm -rf \"%s/%s\"", st.st_mode & S_IFMT, strna(parent_name), name); /* If the target of the symlink was the wrong type, the link needs to be removed instead of the * target, so make sure it is identified as a link and not a directory. */ diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index d58a3d5d6..d774b447a 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -545,7 +545,7 @@ static sd_device *handle_ap(sd_device *parent, char **path) { static int find_real_nvme_parent(sd_device *dev, sd_device **ret) { _cleanup_(sd_device_unrefp) sd_device *nvme = NULL; - const char *sysname, *end; + const char *sysname, *end, *devpath; int r; /* If the device belongs to "nvme-subsystem" (not to be confused with "nvme"), which happens when @@ -577,6 +577,14 @@ static int find_real_nvme_parent(sd_device *dev, sd_device **ret) { if (r < 0) return r; + r = sd_device_get_devpath(nvme, &devpath); + if (r < 0) + return r; + + /* If the 'real parent' is (still) virtual, e.g. for nvmf disks, refuse to set ID_PATH. */ + if (path_startswith(devpath, "/devices/virtual/")) + return -ENXIO; + *ret = TAKE_PTR(nvme); return 0; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 8c8c7cbdd..8ee7d6711 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1090,9 +1090,7 @@ static int rule_add_line(UdevRules *rules, const char *line_str, unsigned line_n if (isempty(line_str)) return 0; - /* We use memdup_suffix0() here, since we want to add a second NUL byte to the end, since possibly - * some parsers might turn this into a "nulstr", which requires an extra NUL at the end. */ - line = memdup_suffix0(line_str, strlen(line_str) + 1); + line = strdup(line_str); if (!line) return log_oom(); @@ -1612,7 +1610,7 @@ static int udev_rule_apply_token_to_event( const char *val; FOREACH_DEVICE_DEVLINK(dev, val) - if (token_match_string(token, strempty(startswith(val, "/dev/")))) + if (token_match_string(token, strempty(startswith(val, "/dev/"))) == (token->op == OP_MATCH)) return token->op == OP_MATCH; return token->op == OP_NOMATCH; } @@ -1642,7 +1640,7 @@ static int udev_rule_apply_token_to_event( const char *val; FOREACH_DEVICE_CURRENT_TAG(dev, val) - if (token_match_string(token, val)) + if (token_match_string(token, val) == (token->op == OP_MATCH)) return token->op == OP_MATCH; return token->op == OP_NOMATCH; } diff --git a/src/udev/udevadm-lock.c b/src/udev/udevadm-lock.c index 35e9999c0..1e5fcb4b9 100644 --- a/src/udev/udevadm-lock.c +++ b/src/udev/udevadm-lock.c @@ -75,6 +75,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, arg_print ? "hVd:b:t:p" : "+hVd:b:t:p", options, NULL)) >= 0) switch (c) { diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index cd3786b41..28a16dbcd 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -62,6 +62,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) switch (c) { diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index 63b0c4dde..e762fca02 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -961,7 +961,7 @@ static int display_services(int argc, char *argv[], void *userdata) { return table_log_print_error(r); } - if (arg_legend) { + if (arg_legend && arg_output != OUTPUT_JSON) { if (table_get_rows(t) > 1) printf("\n%zu services listed.\n", table_get_rows(t) - 1); else @@ -1037,6 +1037,7 @@ static int ssh_authorized_keys(int argc, char *argv[], void *userdata) { log_debug("Chain invoking: %s", s); } + fflush(stdout); execv(chain_invocation[0], chain_invocation); if (errno == ENOENT) /* Let's handle ENOENT gracefully */ log_warning_errno(errno, "Chain executable '%s' does not exist, ignoring chain invocation.", chain_invocation[0]); @@ -1148,6 +1149,10 @@ static int parse_argv(int argc, char *argv[]) { arg_services = l; } + /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long() + * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */ + optind = 0; + for (;;) { int c; diff --git a/src/xdg-autostart-generator/test-xdg-autostart.c b/src/xdg-autostart-generator/test-xdg-autostart.c index e11f3d938..81f85d6b1 100644 --- a/src/xdg-autostart-generator/test-xdg-autostart.c +++ b/src/xdg-autostart-generator/test-xdg-autostart.c @@ -10,7 +10,7 @@ #include "xdg-autostart-service.h" TEST(translate_name) { - _cleanup_free_ char *t; + _cleanup_free_ char *t = NULL; assert_se(t = xdg_autostart_service_translate_name("a-b.blub.desktop")); assert_se(streq(t, "app-a\\x2db.blub@autostart.service")); @@ -26,7 +26,7 @@ static void test_xdg_format_exec_start_one(const char *exec, const char *expecte TEST(xdg_format_exec_start) { _cleanup_free_ char *home = NULL; - _cleanup_free_ char *expected1, *expected2 = NULL; + _cleanup_free_ char *expected1 = NULL, *expected2 = NULL; assert_se(get_home_dir(&home) >= 0); diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c index 3905d4bfe..a174648f5 100644 --- a/src/xdg-autostart-generator/xdg-autostart-service.c +++ b/src/xdg-autostart-generator/xdg-autostart-service.c @@ -350,7 +350,8 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) { r = config_parse(NULL, service->path, NULL, "Desktop Entry\0", xdg_config_item_table_lookup, items, - CONFIG_PARSE_WARN, service, + CONFIG_PARSE_RELAXED | CONFIG_PARSE_WARN, + service, NULL); /* If parsing failed, only hide the file so it will still mask others. */ if (r < 0) { diff --git a/test/README.testsuite b/test/README.testsuite index 40240599a..69ea2ab80 100644 --- a/test/README.testsuite +++ b/test/README.testsuite @@ -99,7 +99,7 @@ INTERACTIVE_DEBUG=1 the test, etc.) The kernel and initrd can be specified with $KERNEL_BIN and $INITRD. (Fedora's -or Debian's default kernel path and initrd are used by default) +or Debian's default kernel path and initrd are used by default.) A script will try to find your qemu binary. If you want to specify a different one with $QEMU_BIN. @@ -107,12 +107,12 @@ one with $QEMU_BIN. Debugging the qemu image ======================== -If you want to log in the testsuite virtual machine, you can specify additional -kernel command line parameter with $KERNEL_APPEND and then log in as root. +If you want to log in the testsuite virtual machine, use INTERACTIVE_DEBUG=1 +and log in as root: -$ sudo make -C test/TEST-01-BASIC KERNEL_APPEND="systemd.unit=multi-user.target" run +$ sudo make -C test/TEST-01-BASIC INTERACTIVE_DEBUG=1 run -Root password is empty. +The root password is empty. Ubuntu CI ========= diff --git a/test/TEST-26-SYSTEMCTL/test.sh b/test/TEST-26-SYSTEMCTL/test.sh index 64accf850..659311be4 100755 --- a/test/TEST-26-SYSTEMCTL/test.sh +++ b/test/TEST-26-SYSTEMCTL/test.sh @@ -7,4 +7,8 @@ TEST_DESCRIPTION="systemctl-related tests" # shellcheck source=test/test-functions . "${TEST_BASE_DIR:?}/test-functions" +test_append_files() ( + image_install script +) + do_test "$@" diff --git a/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string b/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string new file mode 100644 index 000000000..675bed050 --- /dev/null +++ b/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string @@ -0,0 +1 @@ +{"ociVersion":"1.0.0","process":{"args":[]}} diff --git a/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string2 b/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string2 new file mode 100644 index 000000000..fb1269b9c --- /dev/null +++ b/test/fuzz/fuzz-nspawn-oci/invalid-read-magic-string2 @@ -0,0 +1 @@ +{"ociVersion":"1.0.0","process":{"args":[""]}} \ No newline at end of file diff --git a/test/test-fstab-generator.sh b/test/test-fstab-generator.sh index 7c060dfac..5a166ab03 100755 --- a/test/test-fstab-generator.sh +++ b/test/test-fstab-generator.sh @@ -17,6 +17,10 @@ src="$(dirname "$0")/testdata/test-fstab-generator" # fsck(8) is located in /usr/sbin on Debian PATH=$PATH:/usr/sbin +# systemd-pcrfs@.service could be enabled or not, depending on the host state +# of the host system. Override the measurement to avoid the issue. +export SYSTEMD_FORCE_MEASURE=0 + for f in "$src"/test-*.input; do echo "*** Running $f" diff --git a/test/test-functions b/test/test-functions index ae0a99333..41925b4e2 100644 --- a/test/test-functions +++ b/test/test-functions @@ -206,6 +206,7 @@ BASICTOOLS=( seq setfattr setfont + setpriv setsid sfdisk sh @@ -871,8 +872,8 @@ INNER_EOF # Let's make one to prevent unexpected " not found" issues in the future export PATH="/sbin:/bin:/usr/sbin:/usr/bin" -mount -t proc proc /proc -mount -t sysfs sysfs /sys +mountpoint -q /proc || mount -t proc proc /proc +mountpoint -q /sys || mount -t sysfs sysfs /sys mount -o remount,rw / DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT ASAN_RT_PATH=$ASAN_RT_PATH" @@ -1141,7 +1142,7 @@ install_debian_systemd() { ddebug "Install debian files from package $deb" for file in $files; do [ -e "$file" ] || continue - [ -d "$file" ] && continue + [ ! -L "$file" ] && [ -d "$file" ] && continue inst "$file" done done < <(grep -E '^Package:' "${SOURCE_DIR}/debian/control" | cut -d ':' -f 2) @@ -1169,7 +1170,7 @@ install_suse_systemd() { ddebug "Install files from package $p" while read -r f; do [ -e "$f" ] || continue - [ -d "$f" ] && continue + [ ! -L "$f" ] && [ -d "$f" ] && continue inst "$f" done < <(rpm -ql "$p") done @@ -1228,11 +1229,14 @@ install_systemd() { mkdir -p "$initdir/etc/systemd/system/service.d/" echo -e "[Service]\nProtectSystem=no\nProtectHome=no\n" >"$initdir/etc/systemd/system/service.d/99-gcov-override.conf" # Similarly, set ReadWritePaths= to the $BUILD_DIR in the test image - # to make the coverage work with units utilizing DynamicUser=yes. Do - # this only for services from TEST-20, as setting this system-wide - # has many undesirable side-effects - mkdir -p "$initdir/etc/systemd/system/test20-.service.d/" - echo -e "[Service]\nReadWritePaths=${BUILD_DIR:?}\n" >"$initdir/etc/systemd/system/test20-.service.d/99-gcov-rwpaths-override.conf" + # to make the coverage work with units using DynamicUser=yes. Do this + # only for services with test- prefix, as setting this system-wide + # has many undesirable side-effects, as it creates its own namespace. + mkdir -p "$initdir/etc/systemd/system/test-.service.d/" + echo -e "[Service]\nReadWritePaths=${BUILD_DIR:?}\n" >"$initdir/etc/systemd/system/test-.service.d/99-gcov-rwpaths-override.conf" + # Ditto, but for the user daemon + mkdir -p "$initdir/etc/systemd/user/test-.service.d/" + echo -e "[Service]\nReadWritePaths=${BUILD_DIR:?}\n" >"$initdir/etc/systemd/user/test-.service.d/99-gcov-rwpaths-override.conf" fi # If we're built with -Dportabled=false, tests with systemd-analyze @@ -1917,12 +1921,12 @@ EOF - 60000 + 120000 EOF # Bump the client-side timeout in sd-bus as well mkdir -p "$initdir/etc/systemd/system.conf.d" - echo -e '[Manager]\nDefaultEnvironment=SYSTEMD_BUS_TIMEOUT=60' >"$initdir/etc/systemd/system.conf.d/bus-timeout.conf" + echo -e '[Manager]\nDefaultEnvironment=SYSTEMD_BUS_TIMEOUT=120' >"$initdir/etc/systemd/system.conf.d/bus-timeout.conf" fi } @@ -2615,11 +2619,14 @@ inst_binary() { # Same as above, but we need to wrap certain libraries unconditionally # - # chown, getent, login, su, useradd, userdel - dlopen()s (not only) systemd's PAM modules - # ls, stat - pulls in nss_systemd with certain options (like ls -l) when - # nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux) + # chown, getent, login, su, useradd, userdel - dlopen() (not only) systemd's PAM modules + # ls, mkfs.*, mksquashfs, mkswap, setpriv, stat + # - pull in nss_systemd with certain options (like ls -l) when + # nsswitch.conf uses [SUCCESS=merge] (like on Arch Linux) + # delv, dig - pull in nss_resolve if `resolve` is in nsswitch.conf # tar - called by machinectl in TEST-25 - if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ /(chown|getent|login|ls|stat|su|tar|useradd|userdel)$ ]]; then + bin_rx='/(chown|delv|dig|getent|login|ls|mkfs\.[a-z0-9]+|mksquashfs|mkswap|setpriv|stat|su|tar|useradd|userdel)$' + if get_bool "$IS_BUILT_WITH_ASAN" && [[ "$bin" =~ $bin_rx ]]; then wrap_binary=1 fi @@ -3209,7 +3216,8 @@ do_test() { fi test_cleanup if [ $ret -eq 0 ]; then - rm "$TESTLOG" + # $TESTLOG is in $STATEDIR, so clean it up only on success + [[ -n "$STATEDIR" ]] && rm -vfr "$STATEDIR" echo "[OK]" else echo "[FAILED]" diff --git a/test/test-network/conf/21-vlan.netdev.d/override.conf b/test/test-network/conf/21-vlan.netdev.d/override.conf index 3b8d47d9b..c71077d27 100644 --- a/test/test-network/conf/21-vlan.netdev.d/override.conf +++ b/test/test-network/conf/21-vlan.netdev.d/override.conf @@ -3,7 +3,9 @@ MTUBytes=2000 [VLAN] Id=99 -GVRP=true -MVRP=true -LooseBinding=true -ReorderHeader=true +GVRP=yes +MVRP=yes +LooseBinding=yes +ReorderHeader=yes +EgressQOSMaps=0-1 1-3 10-3 6-6 7-7 +IngressQOSMaps=15-13 20-100 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index a04f302f6..5f4a06650 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1228,12 +1228,14 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip -d link show vlan99') print(output) - self.assertRegex(output, ' mtu 2000 ') - self.assertRegex(output, 'REORDER_HDR') - self.assertRegex(output, 'LOOSE_BINDING') - self.assertRegex(output, 'GVRP') - self.assertRegex(output, 'MVRP') - self.assertRegex(output, ' id 99 ') + self.assertIn(' mtu 2000 ', output) + self.assertIn('REORDER_HDR', output) + self.assertIn('LOOSE_BINDING', output) + self.assertIn('GVRP', output) + self.assertIn('MVRP', output) + self.assertIn(' id 99 ', output) + self.assertIn('ingress-qos-map { 4:100 7:13 }', output) + self.assertIn('egress-qos-map { 0:1 1:3 6:6 7:7 10:3 }', output) output = check_output('ip -4 address show dev test1') print(output) @@ -3552,10 +3554,14 @@ class NetworkdTCTests(unittest.TestCase, Utilities): output = check_output('tc -d class show dev dummy98') print(output) - self.assertRegex(output, 'class htb 2:37 root leaf 37:') - 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:') + # Here (:|prio) is a workaround for a bug in iproute2 v6.2.0 caused by + # https://github.com/shemminger/iproute2/commit/010a8388aea11e767ba3a2506728b9ad9760df0e + # which is fixed in v6.3.0 by + # https://github.com/shemminger/iproute2/commit/4e0e56e0ef05387f7f5d8ab41fe6ec6a1897b26d + self.assertRegex(output, 'class htb 2:37 root leaf 37(:|prio) ') + self.assertRegex(output, 'class htb 2:3a root leaf 3a(:|prio) ') + self.assertRegex(output, 'class htb 2:3b root leaf 3b(:|prio) ') + self.assertRegex(output, 'class htb 2:3c root leaf 3c(:|prio) ') self.assertRegex(output, 'prio 1 quantum 4000 rate 1Mbit overhead 100 ceil 500Kbit') self.assertRegex(output, 'burst 123456') self.assertRegex(output, 'cburst 123457') diff --git a/test/testsuite-63.units/test63-issue-24577-dep.service b/test/testsuite-63.units/test63-issue-24577-dep.service new file mode 100644 index 000000000..e332ea474 --- /dev/null +++ b/test/testsuite-63.units/test63-issue-24577-dep.service @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Service] +Type=oneshot +ExecStart=bash -c 'sleep infinity' diff --git a/test/testsuite-63.units/test63-issue-24577.path b/test/testsuite-63.units/test63-issue-24577.path new file mode 100644 index 000000000..80ba1dbe1 --- /dev/null +++ b/test/testsuite-63.units/test63-issue-24577.path @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Path] +PathExists=/tmp/hoge diff --git a/test/testsuite-63.units/test63-issue-24577.service b/test/testsuite-63.units/test63-issue-24577.service new file mode 100644 index 000000000..568518bbf --- /dev/null +++ b/test/testsuite-63.units/test63-issue-24577.service @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Requires=test63-issue-24577-dep.service +After=test63-issue-24577-dep.service + +[Service] +Type=oneshot +ExecStart=bash -c 'sleep infinity' diff --git a/test/udev-test.pl b/test/udev-test.pl index 3099b5746..f6061c41b 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -218,6 +218,8 @@ EOF SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n" SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="1", SYMLINK+="boot_diskXY%n" SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n" +SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK=="link1", SYMLINK+="match" +SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK!="removed1", SYMLINK+="unmatch" EOF }, { @@ -1821,13 +1823,15 @@ EOF devices => [ { devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", - exp_links => ["found"], - not_exp_name => "bad", + exp_links => ["found", "found2"], + not_exp_name => ["bad", "bad2"], }], rules => < "continuations with white only line", + desc => "continuations with space only line", devices => [ { devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", diff --git a/test/units/testsuite-03.sh b/test/units/testsuite-03.sh index 1d4bf3aaa..289d8dac2 100755 --- a/test/units/testsuite-03.sh +++ b/test/units/testsuite-03.sh @@ -34,11 +34,11 @@ grep 'hello\.service' /root/list-jobs.txt && exit 1 systemctl stop sleep.service hello-after-sleep.target # Some basic testing that --show-transaction does something useful -systemctl is-active systemd-importd && { echo 'unexpected success'; exit 1; } +(! systemctl is-active systemd-importd) systemctl -T start systemd-importd systemctl is-active systemd-importd systemctl --show-transaction stop systemd-importd -systemctl is-active systemd-importd && { echo 'unexpected success'; exit 1; } +(! systemctl is-active systemd-importd) # Test for a crash when enqueuing a JOB_NOP when other job already exists systemctl start --no-block hello-after-sleep.target @@ -95,7 +95,7 @@ ELAPSED=$((END_SEC-START_SEC)) # wait5fail fails, so systemctl should fail START_SEC=$(date -u '+%s') -systemctl start --wait wait2.service wait5fail.service && { echo 'unexpected success'; exit 1; } +(! systemctl start --wait wait2.service wait5fail.service) END_SEC=$(date -u '+%s') ELAPSED=$((END_SEC-START_SEC)) [[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1 diff --git a/test/units/testsuite-04.sh b/test/units/testsuite-04.sh index fdc3273fe..94a002191 100755 --- a/test/units/testsuite-04.sh +++ b/test/units/testsuite-04.sh @@ -8,7 +8,8 @@ trap "journalctl --rotate --vacuum-size=16M" EXIT # Rotation/flush test, see https://github.com/systemd/systemd/issues/19895 journalctl --relinquish-var -for _ in {0..50}; do +[[ "$(systemd-detect-virt -v)" == "qemu" ]] && ITERATIONS=10 || ITERATIONS=50 +for ((i = 0; i < ITERATIONS; i++)); do dd if=/dev/urandom bs=1M count=1 | base64 | systemd-cat done journalctl --rotate @@ -74,10 +75,10 @@ journalctl -b -o export --output-fields=MESSAGE,FOO --output-fields=PRIORITY,MES grep -q '^__CURSOR=' /output grep -q '^MESSAGE=foo$' /output grep -q '^PRIORITY=6$' /output -grep '^FOO=' /output && { echo 'unexpected success'; exit 1; } -grep '^SYSLOG_FACILITY=' /output && { echo 'unexpected success'; exit 1; } +(! grep '^FOO=' /output) +(! grep '^SYSLOG_FACILITY=' /output) -# `-b all` negates earlier use of -b (-b and -m are otherwise exclusive) +# '-b all' negates earlier use of -b (-b and -m are otherwise exclusive) journalctl -b -1 -b all -m >/dev/null # -b always behaves like -b0 @@ -175,8 +176,13 @@ sleep 3 systemctl kill --signal=SIGKILL systemd-journald sleep 3 [[ ! -f "/i-lose-my-logs" ]] +systemctl stop forever-print-hola +set +o pipefail # https://github.com/systemd/systemd/issues/15528 -journalctl --follow --file=/var/log/journal/*/* | head -n1 || [[ $? -eq 1 ]] +journalctl --follow --file=/var/log/journal/*/* | head -n1 | grep . +# https://github.com/systemd/systemd/issues/24565 +journalctl --follow --merge | head -n1 | grep . +set -o pipefail touch /testok diff --git a/test/units/testsuite-16.sh b/test/units/testsuite-16.sh index 1b8cd018b..9b8a7bd6f 100755 --- a/test/units/testsuite-16.sh +++ b/test/units/testsuite-16.sh @@ -23,6 +23,25 @@ function wait_for() fi } +function wait_for_timeout() +{ + local unit="$1" + local time="$2" + + while [[ $time -gt 0 ]]; do + if [[ "$(systemctl show --property=Result "$unit")" == "Result=timeout" ]]; then + return 0 + fi + + sleep 1 + time=$((time - 1)) + done + + journalctl -u "$unit" >>"$TESTLOG" + + return 1 +} + # This checks all stages, start, runtime and stop, can be extended by # EXTEND_TIMEOUT_USEC @@ -44,6 +63,53 @@ wait_for fail_start startfail wait_for fail_stop stopfail wait_for fail_runtime runtimefail +# These ensure that RuntimeMaxSec is honored for scope and service units +# when they are created. +runtime_max_sec=5 + +systemd-run \ + --property=RuntimeMaxSec=${runtime_max_sec}s \ + -u runtime-max-sec-test-1.service \ + /usr/bin/sh -c "while true; do sleep 1; done" +wait_for_timeout runtime-max-sec-test-1.service $((runtime_max_sec + 2)) + +systemd-run \ + --property=RuntimeMaxSec=${runtime_max_sec}s \ + --scope \ + -u runtime-max-sec-test-2.scope \ + /usr/bin/sh -c "while true; do sleep 1; done" & +wait_for_timeout runtime-max-sec-test-2.scope $((runtime_max_sec + 2)) + +# These ensure that RuntimeMaxSec is honored for scope and service +# units if the value is changed and then the manager is reloaded. +systemd-run \ + -u runtime-max-sec-test-3.service \ + /usr/bin/sh -c "while true; do sleep 1; done" +mkdir -p /etc/systemd/system/runtime-max-sec-test-3.service.d/ +cat > /etc/systemd/system/runtime-max-sec-test-3.service.d/override.conf << EOF +[Service] +RuntimeMaxSec=${runtime_max_sec}s +EOF +systemctl daemon-reload +wait_for_timeout runtime-max-sec-test-3.service $((runtime_max_sec + 2)) + +systemd-run \ + --scope \ + -u runtime-max-sec-test-4.scope \ + /usr/bin/sh -c "while true; do sleep 1; done" & + +# Wait until the unit is running to avoid race with creating the override. +until systemctl is-active runtime-max-sec-test-4.scope; do + sleep 1 +done +mkdir -p /etc/systemd/system/runtime-max-sec-test-4.scope.d/ +cat > /etc/systemd/system/runtime-max-sec-test-4.scope.d/override.conf << EOF +[Scope] +RuntimeMaxSec=${runtime_max_sec}s +EOF +systemctl daemon-reload +wait_for_timeout runtime-max-sec-test-4.scope $((runtime_max_sec + 2)) + if [[ -f "$TESTLOG" ]]; then # no mv cp "$TESTLOG" /test.log diff --git a/test/units/testsuite-17.06.sh b/test/units/testsuite-17.06.sh index 224063f6a..4d452ff97 100755 --- a/test/units/testsuite-17.06.sh +++ b/test/units/testsuite-17.06.sh @@ -16,20 +16,18 @@ function check_validity() { } function check() { - local i j - - for ((i = 0; i < 2; i++)); do + for _ in {1..2}; do systemctl restart systemd-udevd.service udevadm control --ping udevadm settle check_validity - for ((j = 0; j < 2; j++)); do + for _ in {1..2}; do udevadm trigger -w --action add --subsystem-match=block check_validity done - for ((j = 0; j < 2; j++)); do + for _ in {1..2}; do udevadm trigger -w --action change --subsystem-match=block check_validity done diff --git a/test/units/testsuite-17.07.sh b/test/units/testsuite-17.07.sh index 549107af1..b4dfd904e 100755 --- a/test/units/testsuite-17.07.sh +++ b/test/units/testsuite-17.07.sh @@ -8,8 +8,8 @@ set -o pipefail wait_service_active() {( set +ex - for (( i = 0; i < 20; i++ )); do - if (( i != 0 )); then sleep 0.5; fi + for i in {1..20}; do + (( i > 1 )) && sleep 0.5 if systemctl --quiet is-active "${1?}"; then return 0 fi @@ -19,8 +19,8 @@ wait_service_active() {( wait_service_inactive() {( set +ex - for (( i = 0; i < 20; i++ )); do - if (( i != 0 )); then sleep 0.5; fi + for i in {1..20}; do + (( i > 1 )) && sleep 0.5 systemctl --quiet is-active "${1?}" if [[ "$?" == "3" ]]; then return 0 diff --git a/test/units/testsuite-17.08.sh b/test/units/testsuite-17.08.sh index f740b337f..a49a77dc4 100755 --- a/test/units/testsuite-17.08.sh +++ b/test/units/testsuite-17.08.sh @@ -18,8 +18,8 @@ EOF udevadm control --reload udevadm trigger --settle --action add /dev/null -for ((i = 0; i < 20; i++)); do - ((i == 0)) || sleep .5 +for i in {1..20}; do + ((i > 1)) && sleep .5 ( systemctl -q is-active /dev/test/symlink-to-null-on-add @@ -34,8 +34,8 @@ assert_rc 0 systemctl -q is-active /sys/test/alias-to-null-on-add assert_rc 3 systemctl -q is-active /sys/test/alias-to-null-on-change udevadm trigger --settle --action change /dev/null -for ((i = 0; i < 20; i++)); do - ((i == 0)) || sleep .5 +for i in {1..20}; do + ((i > 1)) && sleep .5 ( ! systemctl -q is-active /dev/test/symlink-to-null-on-add @@ -50,8 +50,8 @@ assert_rc 3 systemctl -q is-active /sys/test/alias-to-null-on-add assert_rc 0 systemctl -q is-active /sys/test/alias-to-null-on-change udevadm trigger --settle --action add /dev/null -for ((i = 0; i < 20; i++)); do - ((i == 0)) || sleep .5 +for i in {1..20}; do + ((i > 1)) && sleep .5 ( systemctl -q is-active /dev/test/symlink-to-null-on-add diff --git a/test/units/testsuite-17.09.sh b/test/units/testsuite-17.09.sh index 01ac5f170..31fc9d684 100755 --- a/test/units/testsuite-17.09.sh +++ b/test/units/testsuite-17.09.sh @@ -15,7 +15,7 @@ KERNEL!="null", GOTO="test-end" ACTION=="remove", GOTO="test-end" # add 100 * 100byte of properties -$(for ((i = 0; i < 100; i++)); do printf 'ENV{XXX%03i}="0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"\n' "$i"; done) +$(for i in {1..100}; do printf 'ENV{XXX%03i}="0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"\n' "$i"; done) LABEL="test-end" EOF @@ -46,7 +46,7 @@ for _ in {1..40}; do fi FOUND=1 - for ((i = 0; i < 100; i++)); do + for i in {1..100}; do if ! grep -F "$(printf 'XXX%03i=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' "$i")" "$TMPDIR"/monitor.txt; then FOUND= break diff --git a/test/units/testsuite-18.sh b/test/units/testsuite-18.sh index e9d7c5bfc..44b792f00 100755 --- a/test/units/testsuite-18.sh +++ b/test/units/testsuite-18.sh @@ -4,7 +4,7 @@ set -eux set -o pipefail systemd-run --wait -p FailureAction=poweroff true -systemd-run --wait -p SuccessAction=poweroff false && { echo 'unexpected success'; exit 1; } +(! systemd-run --wait -p SuccessAction=poweroff false) if ! test -f /firstphase ; then echo OK >/firstphase diff --git a/test/units/testsuite-19.sh b/test/units/testsuite-19.sh index 6ce6d3d42..1e705ea72 100755 --- a/test/units/testsuite-19.sh +++ b/test/units/testsuite-19.sh @@ -7,37 +7,37 @@ test_scope_unpriv_delegation() { useradd test ||: trap "userdel -r test" RETURN - systemd-run --uid=test -p User=test -p Delegate=yes --slice workload.slice --unit workload0.scope --scope \ - test -w /sys/fs/cgroup/workload.slice/workload0.scope -a \ - -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.procs -a \ - -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.subtree_control + systemd-run --uid=test -p User=test -p Delegate=yes --slice workload.slice --unit test-workload0.scope --scope \ + test -w /sys/fs/cgroup/workload.slice/test-workload0.scope -a \ + -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.procs -a \ + -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.subtree_control } if grep -q cgroup2 /proc/filesystems ; then - systemd-run --wait --unit=test0.service -p "DynamicUser=1" -p "Delegate=" \ - test -w /sys/fs/cgroup/system.slice/test0.service/ -a \ - -w /sys/fs/cgroup/system.slice/test0.service/cgroup.procs -a \ - -w /sys/fs/cgroup/system.slice/test0.service/cgroup.subtree_control + systemd-run --wait --unit=test-0.service -p "DynamicUser=1" -p "Delegate=" \ + test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \ + -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.procs -a \ + -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.subtree_control - systemd-run --wait --unit=test1.service -p "DynamicUser=1" -p "Delegate=memory pids" \ - grep -q memory /sys/fs/cgroup/system.slice/test1.service/cgroup.controllers + systemd-run --wait --unit=test-1.service -p "DynamicUser=1" -p "Delegate=memory pids" \ + grep -q memory /sys/fs/cgroup/system.slice/test-1.service/cgroup.controllers - systemd-run --wait --unit=test2.service -p "DynamicUser=1" -p "Delegate=memory pids" \ - grep -q pids /sys/fs/cgroup/system.slice/test2.service/cgroup.controllers + systemd-run --wait --unit=test-2.service -p "DynamicUser=1" -p "Delegate=memory pids" \ + grep -q pids /sys/fs/cgroup/system.slice/test-2.service/cgroup.controllers # "io" is not among the controllers enabled by default for all units, verify that grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers # Run a service with "io" enabled, and verify it works - systemd-run --wait --unit=test3.service -p "IOAccounting=yes" -p "Slice=system-foo-bar-baz.slice" \ - grep -q io /sys/fs/cgroup/system.slice/system-foo.slice/system-foo-bar.slice/system-foo-bar-baz.slice/test3.service/cgroup.controllers + systemd-run --wait --unit=test-3.service -p "IOAccounting=yes" -p "Slice=system-foo-bar-baz.slice" \ + grep -q io /sys/fs/cgroup/system.slice/system-foo.slice/system-foo-bar.slice/system-foo-bar-baz.slice/test-3.service/cgroup.controllers # We want to check if "io" is removed again from the controllers # list. However, PID 1 (rightfully) does this asynchronously. In order # to force synchronization on this, let's start a short-lived service # which requires PID 1 to refresh the cgroup tree, so that we can # verify that this all works. - systemd-run --wait --unit=test4.service true + systemd-run --wait --unit=test-4.service true # And now check again, "io" should have vanished grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers diff --git a/test/units/testsuite-20.sh b/test/units/testsuite-20.sh index 338769aac..6ce992f41 100755 --- a/test/units/testsuite-20.sh +++ b/test/units/testsuite-20.sh @@ -13,8 +13,8 @@ INTERNALPID=$! disown # Start a test process outside of our own cgroup -systemd-run -p DynamicUser=1 --unit=test20-sleep.service /bin/sleep infinity -EXTERNALPID="$(systemctl show -P MainPID test20-sleep.service)" +systemd-run -p DynamicUser=1 --unit=test-sleep.service /bin/sleep infinity +EXTERNALPID="$(systemctl show -P MainPID test-sleep.service)" # Update our own main PID to the external test PID, this should work systemd-notify MAINPID="$EXTERNALPID" @@ -54,7 +54,7 @@ test "$(systemctl show -P MainPID testsuite-20.service)" -eq "$INTERNALPID" systemd-notify --uid=1000 MAINPID=$$ test "$(systemctl show -P MainPID testsuite-20.service)" -eq $$ -cat >/tmp/test20-mainpid.sh </tmp/test-mainpid.sh </run/mainpidsh/pid EOF -chmod +x /tmp/test20-mainpid.sh +chmod +x /tmp/test-mainpid.sh -systemd-run --unit=test20-mainpidsh.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh -p PIDFile=/run/mainpidsh/pid /tmp/test20-mainpid.sh -test "$(systemctl show -P MainPID test20-mainpidsh.service)" -eq "$(cat /run/mainpidsh/pid)" +systemd-run --unit=test-mainpidsh.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh -p PIDFile=/run/mainpidsh/pid /tmp/test-mainpid.sh +test "$(systemctl show -P MainPID test-mainpidsh.service)" -eq "$(cat /run/mainpidsh/pid)" -cat >/tmp/test20-mainpid2.sh </tmp/test-mainpid2.sh </run/mainpidsh2/pid chown 1001:1001 /run/mainpidsh2/pid EOF -chmod +x /tmp/test20-mainpid2.sh +chmod +x /tmp/test-mainpid2.sh -systemd-run --unit=test20-mainpidsh2.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh2 -p PIDFile=/run/mainpidsh2/pid /tmp/test20-mainpid2.sh -test "$(systemctl show -P MainPID test20-mainpidsh2.service)" -eq "$(cat /run/mainpidsh2/pid)" +systemd-run --unit=test-mainpidsh2.service -p StandardOutput=tty -p StandardError=tty -p Type=forking -p RuntimeDirectory=mainpidsh2 -p PIDFile=/run/mainpidsh2/pid /tmp/test-mainpid2.sh +test "$(systemctl show -P MainPID test-mainpidsh2.service)" -eq "$(cat /run/mainpidsh2/pid)" -cat >/dev/shm/test20-mainpid3.sh </dev/shm/test-mainpid3.sh </testok diff --git a/test/units/testsuite-22.03.sh b/test/units/testsuite-22.03.sh index a9df3d6bd..6fce4c070 100755 --- a/test/units/testsuite-22.03.sh +++ b/test/units/testsuite-22.03.sh @@ -38,7 +38,7 @@ test "$(stat -c %U:%G:%a /tmp/f/1)" = "daemon:daemon:666" mkfifo /tmp/f/fifo chmod 644 /tmp/f/fifo -systemd-tmpfiles --create - </tmp/F/rw-fs/foo -systemd-tmpfiles --create - </tmp/F/rw-fs/foo -systemd-tmpfiles --create - < fails. -systemd-tmpfiles --create - </testok diff --git a/test/units/testsuite-26.sh b/test/units/testsuite-26.sh index 37ae6069b..98ffe56e8 100755 --- a/test/units/testsuite-26.sh +++ b/test/units/testsuite-26.sh @@ -48,6 +48,9 @@ echo "disable $UNIT_NAME" >/run/systemd/system-preset/99-systemd-test.preset systemctl daemon-reload +# Double free when editing a template unit (#26483) +EDITOR='true' script -ec 'systemctl edit user@0' /dev/null + # Argument help systemctl --state help systemctl --signal help @@ -397,5 +400,17 @@ EOF systemctl stop issue-24990 fi +# %J in WantedBy= causes ABRT (#26467) +cat >/run/systemd/system/test-WantedBy.service </etc/systemd/system/testservice.service </run/systemd/system/test-service.service </etc/systemd/system/testservice.service </run/systemd/system/test-service.service </etc/systemd/system/tmp-hoge.mount </run/systemd/system/tmp-hoge.mount </etc/systemd/system/testservice.socket </run/systemd/system/test-service.socket </testok diff --git a/test/units/testsuite-34.sh b/test/units/testsuite-34.sh index 2172f7434..0bc3adc9b 100755 --- a/test/units/testsuite-34.sh +++ b/test/units/testsuite-34.sh @@ -22,8 +22,7 @@ test_directory() { systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz:yyy test -f "${path}"/yyy/test systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}=zzz:xxx zzz:xxx2" -p TemporaryFileSystem="${path}" bash -c "test -f ${path}/xxx/test && test -f ${path}/xxx2/test" systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz:xxx -p TemporaryFileSystem="${path}":ro test -f "${path}"/xxx/test - systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing \ - && { echo 'unexpected success'; exit 1; } + (! systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing) test -d "${path}"/zzz test ! -L "${path}"/zzz @@ -47,8 +46,7 @@ test_directory() { systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=1 -p "${directory}=zzz:xxx zzz:xxx2" \ -p TemporaryFileSystem="${path}" -p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env bash -c "test -f ${path}/xxx/test && test -f ${path}/xxx2/test" systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=1 -p "${directory}"=zzz:xxx -p TemporaryFileSystem="${path}":ro test -f "${path}"/xxx/test - systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=1 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing \ - && { echo 'unexpected success'; exit 1; } + (! systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=1 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing) test -L "${path}"/zzz test -d "${path}"/private/zzz @@ -71,8 +69,7 @@ test_directory() { systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz:xxx -p TemporaryFileSystem="${path}" test -f "${path}"/xxx/test systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}=zzz:xxx zzz:xxx2" -p TemporaryFileSystem="${path}" bash -c "test -f ${path}/xxx/test && test -f ${path}/xxx2/test" systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz:xxx -p TemporaryFileSystem="${path}":ro test -f "${path}"/xxx/test - systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing \ - && { echo 'unexpected success'; exit 1; } + (! systemd-run --wait -p RuntimeDirectoryPreserve=yes -p DynamicUser=0 -p "${directory}"=zzz test -f "${path}"/zzz/test-missing) test -d "${path}"/zzz test ! -L "${path}"/zzz diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh index 85925f247..8159b1b28 100755 --- a/test/units/testsuite-35.sh +++ b/test/units/testsuite-35.sh @@ -330,8 +330,8 @@ EOF systemctl restart getty@tty2.service # check session - for ((i = 0; i < 30; i++)); do - (( i != 0 )) && sleep 1 + for i in {1..30}; do + (( i > 1 )) && sleep 1 check_session && break done check_session diff --git a/test/units/testsuite-39.sh b/test/units/testsuite-39.sh index 5b77bbbaf..dbeb1df89 100755 --- a/test/units/testsuite-39.sh +++ b/test/units/testsuite-39.sh @@ -20,7 +20,7 @@ systemctl daemon-reload systemctl start "$SERVICE_NAME" systemctl status "$SERVICE_NAME" # The reload SHOULD fail but SHOULD NOT affect the service state -systemctl reload "$SERVICE_NAME" && { echo 'unexpected success'; exit 1; } +(! systemctl reload "$SERVICE_NAME") systemctl status "$SERVICE_NAME" systemctl stop "$SERVICE_NAME" @@ -38,7 +38,7 @@ systemctl daemon-reload systemctl start "$SERVICE_NAME" systemctl status "$SERVICE_NAME" # The reload SHOULD fail but SHOULD NOT affect the service state -systemctl reload "$SERVICE_NAME" && { echo 'unexpected success'; exit 1; } +(! systemctl reload "$SERVICE_NAME") systemctl status "$SERVICE_NAME" systemctl stop "$SERVICE_NAME" diff --git a/test/units/testsuite-41.sh b/test/units/testsuite-41.sh index 13bc684c2..96b38c517 100755 --- a/test/units/testsuite-41.sh +++ b/test/units/testsuite-41.sh @@ -9,15 +9,14 @@ MAX_SECS=60 systemd-analyze log-level debug # test one: Restart=on-failure should restart the service -systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1" \ - && { echo 'unexpected success'; exit 1; } +(! systemd-run --unit=one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1") for ((secs = 0; secs < MAX_SECS; secs++)); do - [[ "$(systemctl show one.service -P NRestarts)" -le 0 ]] || break - sleep 1 + [[ "$(systemctl show one.service -P NRestarts)" -le 0 ]] || break + sleep 1 done if [[ "$(systemctl show one.service -P NRestarts)" -le 0 ]]; then - exit 1 + exit 1 fi TMP_FILE="/tmp/test-41-oneshot-restart-test" @@ -26,27 +25,26 @@ TMP_FILE="/tmp/test-41-oneshot-restart-test" # test two: make sure StartLimitBurst correctly limits the number of restarts # and restarts execution of the unit from the first ExecStart= -systemd-run --unit=two \ +(! systemd-run --unit=two \ -p StartLimitIntervalSec=120 \ -p StartLimitBurst=3 \ -p Type=oneshot \ -p Restart=on-failure \ - -p ExecStart="/bin/bash -c \"printf a >> $TMP_FILE\"" /bin/bash -c "exit 1" \ - && { echo 'unexpected success'; exit 1; } + -p ExecStart="/bin/bash -c \"printf a >> $TMP_FILE\"" /bin/bash -c "exit 1") # wait for at least 3 restarts for ((secs = 0; secs < MAX_SECS; secs++)); do - [[ $(cat $TMP_FILE) != "aaa" ]] || break - sleep 1 + [[ $(cat $TMP_FILE) != "aaa" ]] || break + sleep 1 done if [[ $(cat $TMP_FILE) != "aaa" ]]; then - exit 1 + exit 1 fi # wait for 5 more seconds to make sure there aren't excess restarts sleep 5 if [[ $(cat $TMP_FILE) != "aaa" ]]; then - exit 1 + exit 1 fi systemd-analyze log-level info diff --git a/test/units/testsuite-42.sh b/test/units/testsuite-42.sh index 9476df86d..b78d5b7a4 100755 --- a/test/units/testsuite-42.sh +++ b/test/units/testsuite-42.sh @@ -4,18 +4,20 @@ set -eux systemd-analyze log-level debug -systemd-run --unit=simple1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple -p ExecStopPost='/bin/touch /run/simple1' true +systemd-run --unit=simple1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple \ + -p ExecStopPost='/bin/touch /run/simple1' true test -f /run/simple1 -systemd-run --unit=simple2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple -p ExecStopPost='/bin/touch /run/simple2' false \ - && { echo 'unexpected success'; exit 1; } +(! systemd-run --unit=simple2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=simple \ + -p ExecStopPost='/bin/touch /run/simple2' false) test -f /run/simple2 -systemd-run --unit=exec1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec -p ExecStopPost='/bin/touch /run/exec1' sleep 1 +systemd-run --unit=exec1.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec \ + -p ExecStopPost='/bin/touch /run/exec1' sleep 1 test -f /run/exec1 -systemd-run --unit=exec2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec -p ExecStopPost='/bin/touch /run/exec2' sh -c 'sleep 1; false' \ - && { echo 'unexpected success'; exit 1; } +(! systemd-run --unit=exec2.service --wait -p StandardOutput=tty -p StandardError=tty -p Type=exec \ + -p ExecStopPost='/bin/touch /run/exec2' sh -c 'sleep 1; false') test -f /run/exec2 cat >/tmp/forking1.sh </tmp/forking2.sh </tmp/forking2.sh </tmp/notify1.sh < /proc/sys/user/max_user_namespaces" \ - && { echo 'unexpected success'; exit 1; } + sh -c "echo 0 > /proc/sys/user/max_user_namespaces") -runas testuser systemd-run --wait --user --unit=test-kernel-mod \ +(! runas testuser systemd-run --wait --user --unit=test-kernel-mod \ -p PrivateUsers=yes -p ProtectKernelModules=yes \ - sh -c "modprobe -r overlay && modprobe overlay" \ - && { echo 'unexpected success'; exit 1; } + sh -c "modprobe -r overlay && modprobe overlay") if sysctl kernel.dmesg_restrict=0; then - runas testuser systemd-run --wait --user --unit=test-kernel-log \ + (! runas testuser systemd-run --wait --user --unit=test-kernel-log \ -p PrivateUsers=yes -p ProtectKernelLogs=yes -p LogNamespace=yes \ - dmesg \ - && { echo 'unexpected success'; exit 1; } + dmesg) fi unsquashfs -no-xattrs -d /tmp/img /usr/share/minimal_0.raw diff --git a/test/units/testsuite-44.sh b/test/units/testsuite-44.sh index 49c240ff8..da779a690 100755 --- a/test/units/testsuite-44.sh +++ b/test/units/testsuite-44.sh @@ -11,7 +11,7 @@ journalctl -o cat --namespace=foobar >/tmp/hello-world journalctl -o cat >/tmp/no-hello-world grep "^hello world$" /tmp/hello-world -grep "^hello world$" /tmp/no-hello-world && { echo 'unexpected success'; exit 1; } +(! grep "^hello world$" /tmp/no-hello-world) systemd-analyze log-level info diff --git a/test/units/testsuite-45.sh b/test/units/testsuite-45.sh index 24e888c58..e872c9657 100755 --- a/test/units/testsuite-45.sh +++ b/test/units/testsuite-45.sh @@ -7,6 +7,27 @@ set -o pipefail # shellcheck source=test/units/assert.sh . "$(dirname "$0")"/assert.sh +test_timedatectl() { + timedatectl --no-pager --help + timedatectl --version + + timedatectl + timedatectl --no-ask-password + timedatectl status --machine=testuser@.host + timedatectl status + timedatectl show + timedatectl show --all + timedatectl show -p NTP + timedatectl show -p NTP --value + timedatectl list-timezones + + if ! systemd-detect-virt -qc; then + systemctl enable --runtime --now systemd-timesyncd + timedatectl timesync-status + timedatectl show-timesync + fi +} + restore_timezone() { if [[ -f /tmp/timezone.bak ]]; then mv /tmp/timezone.bak /etc/timezone @@ -191,8 +212,8 @@ start_mon() { } wait_mon() { - for ((i = 0; i < 10; i++)); do - if (( i != 0 )); then sleep 1; fi + for i in {1..10}; do + (( i > 1 )) && sleep 1 if grep -q "$1" "$mon"; then break; fi done assert_in "$2" "$(cat "$mon")" @@ -222,8 +243,8 @@ EOF echo 'disable NTP' timedatectl set-ntp false - for ((i = 0; i < 10; i++)); do - if (( i != 0 )); then sleep 1; fi + for i in {1..10}; do + (( i > 1 )) && sleep 1 if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=inactive" ]]; then break; fi @@ -237,8 +258,8 @@ EOF timedatectl set-ntp true wait_mon "NTP" "BOOLEAN true" assert_ntp "true" - for ((i = 0; i < 10; i++)); do - if (( i != 0 )); then sleep 1; fi + for i in {1..10}; do + (( i > 1 )) && sleep 1 if [[ "$(systemctl show systemd-timesyncd --property ActiveState)" == "ActiveState=active" ]]; then break; fi @@ -256,6 +277,7 @@ EOF : >/failed +test_timedatectl test_timezone test_adjtime test_ntp diff --git a/test/units/testsuite-46.sh b/test/units/testsuite-46.sh index 9d090654b..ec80b7147 100755 --- a/test/units/testsuite-46.sh +++ b/test/units/testsuite-46.sh @@ -27,9 +27,9 @@ inspect() { } wait_for_state() { - for ((i = 0; i < 10; i++)) ; do + for i in {1..10}; do + (( i > 1 )) && sleep 0.5 homectl inspect "$1" | grep -qF "State: $2" && break - sleep .5 done } @@ -153,14 +153,12 @@ if ! systemd-detect-virt -cq ; then fi PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz -PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz \ - && { echo 'unexpected success'; exit 1; } +(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) PASSWORD=xEhErW0ndafV4s homectl with test-user -- touch /home/test-user/xyz PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz PASSWORD=xEhErW0ndafV4s homectl with test-user -- rm /home/test-user/xyz PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz -PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz \ - && { echo 'unexpected success'; exit 1; } +(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) wait_for_state test-user inactive homectl remove test-user @@ -172,6 +170,142 @@ if ! systemd-detect-virt -cq ; then homectl remove test-user2 fi +# userdbctl tests +export PAGER= + +# Create a couple of user/group records to test io.systemd.DropIn +# See docs/USER_RECORD.md and docs/GROUP_RECORD.md +mkdir -p /run/userdb/ +cat >"/run/userdb/dropingroup.group" <<\EOF +{ + "groupName" : "dropingroup", + "gid" : 1000000 +} +EOF +cat >"/run/userdb/dropinuser.user" <<\EOF +{ + "userName" : "dropinuser", + "uid" : 2000000, + "realName" : "๐Ÿฑ", + "memberOf" : [ + "dropingroup" + ] +} +EOF +cat >"/run/userdb/dropinuser.user-privileged" <<\EOF +{ + "privileged" : { + "hashedPassword" : [ + "$6$WHBKvAFFT9jKPA4k$OPY4D4TczKN/jOnJzy54DDuOOagCcvxxybrwMbe1SVdm.Bbr.zOmBdATp.QrwZmvqyr8/SafbbQu.QZ2rRvDs/" + ], + "sshAuthorizedKeys" : [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA//dxI2xLg4MgxIKKZv1nqwTEIlE/fdakii2Fb75pG+ foo@bar.tld", + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMlaqG2rTMje5CQnfjXJKmoSpEVJ2gWtx4jBvsQbmee2XbU/Qdq5+SRisssR9zVuxgg5NA5fv08MgjwJQMm+csc= hello@world.tld" + ] + } +} +EOF +# Set permissions and create necessary symlinks as described in nss-systemd(8) +chmod 0600 "/run/userdb/dropinuser.user-privileged" +ln -svrf "/run/userdb/dropingroup.group" "/run/userdb/1000000.group" +ln -svrf "/run/userdb/dropinuser.user" "/run/userdb/2000000.user" +ln -svrf "/run/userdb/dropinuser.user-privileged" "/run/userdb/2000000.user-privileged" + +userdbctl +userdbctl --version +userdbctl --help --no-pager +userdbctl --no-legend +userdbctl --output=classic +userdbctl --output=friendly +userdbctl --output=table +userdbctl --output=json | jq +userdbctl -j --json=pretty | jq +userdbctl -j --json=short | jq +userdbctl --with-varlink=no + +userdbctl user +userdbctl user testuser +userdbctl user root +userdbctl user testuser root +userdbctl user -j testuser root | jq +# Check only UID for the nobody user, since the name is build-configurable +userdbctl user --with-nss=no --synthesize=yes +userdbctl user --with-nss=no --synthesize=yes 0 root 65534 +userdbctl user dropinuser +userdbctl user 2000000 +userdbctl user --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropinuser +userdbctl user --with-nss=no 2000000 +(! userdbctl user '') +(! userdbctl user ๐Ÿฑ) +(! userdbctl user ๐Ÿฑ '' bar) +(! userdbctl user i-do-not-exist) +(! userdbctl user root i-do-not-exist testuser) +(! userdbctl user --with-nss=no --synthesize=no 0 root 65534) +(! userdbctl user -N root nobody) +(! userdbctl user --with-dropin=no dropinuser) +(! userdbctl user --with-dropin=no 2000000) + +userdbctl group +userdbctl group testuser +userdbctl group root +userdbctl group testuser root +userdbctl group -j testuser root | jq +# Check only GID for the nobody group, since the name is build-configurable +userdbctl group --with-nss=no --synthesize=yes +userdbctl group --with-nss=no --synthesize=yes 0 root 65534 +userdbctl group dropingroup +userdbctl group 1000000 +userdbctl group --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropingroup +userdbctl group --with-nss=no 1000000 +(! userdbctl group '') +(! userdbctl group ๐Ÿฑ) +(! userdbctl group ๐Ÿฑ '' bar) +(! userdbctl group i-do-not-exist) +(! userdbctl group root i-do-not-exist testuser) +(! userdbctl group --with-nss=no --synthesize=no 0 root 65534) +(! userdbctl group --with-dropin=no dropingroup) +(! userdbctl group --with-dropin=no 1000000) + +userdbctl users-in-group +userdbctl users-in-group testuser +userdbctl users-in-group testuser root +userdbctl users-in-group -j testuser root | jq +userdbctl users-in-group ๐Ÿฑ +(! userdbctl users-in-group '') +(! userdbctl users-in-group foo '' bar) + +userdbctl groups-of-user +userdbctl groups-of-user testuser +userdbctl groups-of-user testuser root +userdbctl groups-of-user -j testuser root | jq +userdbctl groups-of-user ๐Ÿฑ +(! userdbctl groups-of-user '') +(! userdbctl groups-of-user foo '' bar) + +userdbctl services +userdbctl services -j | jq + +userdbctl ssh-authorized-keys dropinuser | tee /tmp/authorized-keys +grep "ssh-ed25519" /tmp/authorized-keys +grep "ecdsa-sha2-nistp256" /tmp/authorized-keys +echo "my-top-secret-key ๐Ÿฑ" >/tmp/my-top-secret-key +userdbctl ssh-authorized-keys dropinuser --chain /bin/cat /tmp/my-top-secret-key | tee /tmp/authorized-keys +grep "ssh-ed25519" /tmp/authorized-keys +grep "ecdsa-sha2-nistp256" /tmp/authorized-keys +grep "my-top-secret-key ๐Ÿฑ" /tmp/authorized-keys +(! userdbctl ssh-authorized-keys ๐Ÿฑ) +(! userdbctl ssh-authorized-keys dropin-user --chain) +(! userdbctl ssh-authorized-keys dropin-user --chain '') +(! SYSTEMD_LOG_LEVEL=debug userdbctl ssh-authorized-keys dropin-user --chain /bin/false) + +(! userdbctl '') +for opt in json multiplexer output synthesize with-dropin with-nss with-varlink; do + (! userdbctl "--$opt=''") + (! userdbctl "--$opt='๐Ÿฑ'") + (! userdbctl "--$opt=foo") + (! userdbctl "--$opt=foo" "--$opt=''" "--$opt=๐Ÿฑ") +done + systemd-analyze log-level info echo OK >/testok diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index 3ab020d68..2065caf90 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -356,8 +356,8 @@ systemctl is-active testservice-50e.service # ExtensionDirectories will set up an overlay 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-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh) +(! systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh) 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" diff --git a/test/units/testsuite-54.sh b/test/units/testsuite-54.sh index dc0c5f554..3be507636 100755 --- a/test/units/testsuite-54.sh +++ b/test/units/testsuite-54.sh @@ -7,13 +7,15 @@ systemd-analyze log-level debug # Verify that the creds are properly loaded and we can read them from the service's unpriv user systemd-run -p LoadCredential=passwd:/etc/passwd \ - -p LoadCredential=shadow:/etc/shadow \ - -p SetCredential=dog:wuff \ - -p DynamicUser=1 \ - --wait \ - --pipe \ - cat '${CREDENTIALS_DIRECTORY}/passwd' '${CREDENTIALS_DIRECTORY}/shadow' '${CREDENTIALS_DIRECTORY}/dog' >/tmp/ts54-concat -( cat /etc/passwd /etc/shadow && echo -n wuff ) | cmp /tmp/ts54-concat + -p LoadCredential=shadow:/etc/shadow \ + -p SetCredential=dog:wuff \ + -p DynamicUser=1 \ + --unit=test-54-unpriv.service \ + --wait \ + --pipe \ + cat '${CREDENTIALS_DIRECTORY}/passwd' '${CREDENTIALS_DIRECTORY}/shadow' '${CREDENTIALS_DIRECTORY}/dog' \ + >/tmp/ts54-concat +(cat /etc/passwd /etc/shadow && echo -n wuff) | cmp /tmp/ts54-concat rm /tmp/ts54-concat # Test that SetCredential= acts as fallback for LoadCredential= @@ -71,20 +73,20 @@ if [ "$expected_credential" != "" ] ; then systemd-run -p AssertCredential="$expected_credential" -p Type=oneshot true # And this should fail - systemd-run -p AssertCredential="undefinedcredential" -p Type=oneshot true && { echo 'unexpected success'; exit 1; } + (! systemd-run -p AssertCredential="undefinedcredential" -p Type=oneshot true) fi # Verify that the creds are immutable -systemd-run -p LoadCredential=passwd:/etc/passwd \ - -p DynamicUser=1 \ - --wait \ - touch '${CREDENTIALS_DIRECTORY}/passwd' \ - && { echo 'unexpected success'; exit 1; } -systemd-run -p LoadCredential=passwd:/etc/passwd \ - -p DynamicUser=1 \ - --wait \ - rm '${CREDENTIALS_DIRECTORY}/passwd' \ - && { echo 'unexpected success'; exit 1; } +(! systemd-run -p LoadCredential=passwd:/etc/passwd \ + -p DynamicUser=1 \ + --unit=test-54-immutable-touch.service \ + --wait \ + touch '${CREDENTIALS_DIRECTORY}/passwd') +(! systemd-run -p LoadCredential=passwd:/etc/passwd \ + -p DynamicUser=1 \ + --unit=test-54-immutable-rm.service \ + --wait \ + rm '${CREDENTIALS_DIRECTORY}/passwd') # Check directory-based loading mkdir -p /tmp/ts54-creds/sub @@ -93,14 +95,15 @@ echo -n b >/tmp/ts54-creds/bar echo -n c >/tmp/ts54-creds/baz echo -n d >/tmp/ts54-creds/sub/qux systemd-run -p LoadCredential=cred:/tmp/ts54-creds \ - -p DynamicUser=1 \ - --wait \ - --pipe \ - cat '${CREDENTIALS_DIRECTORY}/cred_foo' \ - '${CREDENTIALS_DIRECTORY}/cred_bar' \ - '${CREDENTIALS_DIRECTORY}/cred_baz' \ - '${CREDENTIALS_DIRECTORY}/cred_sub_qux' >/tmp/ts54-concat -( echo -n abcd ) | cmp /tmp/ts54-concat + -p DynamicUser=1 \ + --unit=test-54-dir.service \ + --wait \ + --pipe \ + cat '${CREDENTIALS_DIRECTORY}/cred_foo' \ + '${CREDENTIALS_DIRECTORY}/cred_bar' \ + '${CREDENTIALS_DIRECTORY}/cred_baz' \ + '${CREDENTIALS_DIRECTORY}/cred_sub_qux' >/tmp/ts54-concat +cmp /tmp/ts54-concat <(echo -n abcd) rm /tmp/ts54-concat rm -rf /tmp/ts54-creds @@ -111,22 +114,31 @@ if systemctl --version | grep -q -- +OPENSSL ; then systemd-creds decrypt --name=test-54 /tmp/test-54-ciphertext | cmp /tmp/test-54-plaintext systemd-run -p LoadCredentialEncrypted=test-54:/tmp/test-54-ciphertext \ - --wait \ - --pipe \ - cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext + --wait \ + --pipe \ + cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext echo -n $RANDOM >/tmp/test-54-plaintext systemd-creds encrypt --name=test-54 /tmp/test-54-plaintext /tmp/test-54-ciphertext systemd-creds decrypt --name=test-54 /tmp/test-54-ciphertext | cmp /tmp/test-54-plaintext systemd-run -p SetCredentialEncrypted=test-54:"$(cat /tmp/test-54-ciphertext)" \ - --wait \ - --pipe \ - cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext + --wait \ + --pipe \ + cat '${CREDENTIALS_DIRECTORY}/test-54' | cmp /tmp/test-54-plaintext rm /tmp/test-54-plaintext /tmp/test-54-ciphertext fi +# https://github.com/systemd/systemd/issues/27275 +systemd-run -p DynamicUser=yes -p 'LoadCredential=os:/etc/os-release' \ + -p 'ExecStartPre=true' \ + -p 'ExecStartPre=systemd-creds cat os' \ + --unit=test-54-exec-start.service \ + --wait \ + --pipe \ + true | cmp /etc/os-release + systemd-analyze log-level info echo OK >/testok diff --git a/test/units/testsuite-56.sh b/test/units/testsuite-56.sh index ffdd35287..f81c6ddf1 100755 --- a/test/units/testsuite-56.sh +++ b/test/units/testsuite-56.sh @@ -35,15 +35,13 @@ systemd-run --wait --unit=two -p Type=notify -p ExitType=cgroup \ /tmp/test56-exit-cgroup.sh 'systemctl stop two' # false exec condition: systemd-run should exit immediately with status code: 1 -systemd-run --wait --unit=three -p Type=notify -p ExitType=cgroup \ +(! systemd-run --wait --unit=three -p Type=notify -p ExitType=cgroup \ -p ExecCondition=false \ - /tmp/test56-exit-cgroup.sh \ - && { echo 'unexpected success'; exit 1; } + /tmp/test56-exit-cgroup.sh) # service should exit uncleanly (main process exits with SIGKILL) -systemd-run --wait --unit=four -p Type=notify -p ExitType=cgroup \ - /tmp/test56-exit-cgroup.sh 'systemctl kill --signal 9 four' \ - && { echo 'unexpected success'; exit 1; } +(! systemd-run --wait --unit=four -p Type=notify -p ExitType=cgroup \ + /tmp/test56-exit-cgroup.sh 'systemctl kill --signal 9 four') # Multiple level process tree, parent process exits quickly diff --git a/test/units/testsuite-57-retry-fail.service b/test/units/testsuite-57-retry-fail.service new file mode 100644 index 000000000..67f34079d --- /dev/null +++ b/test/units/testsuite-57-retry-fail.service @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Failed Dependency Unit + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/sh -c "if [ -f /tmp/testsuite-57-retry-fail ]; then exit 0; else exit 1; fi" +Restart=no diff --git a/test/units/testsuite-57-retry-upheld.service b/test/units/testsuite-57-retry-upheld.service new file mode 100644 index 000000000..2f718a61f --- /dev/null +++ b/test/units/testsuite-57-retry-upheld.service @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Upheld Unit +Requires=testsuite-57-retry-fail.service +After=testsuite-57-retry-fail.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/echo ok diff --git a/test/units/testsuite-57-retry-uphold.service b/test/units/testsuite-57-retry-uphold.service new file mode 100644 index 000000000..a01b131ed --- /dev/null +++ b/test/units/testsuite-57-retry-uphold.service @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Upholding Unit +Upholds=testsuite-57-retry-upheld.service + +[Service] +ExecStart=/bin/sleep infinity diff --git a/test/units/testsuite-57.sh b/test/units/testsuite-57.sh index 66d946beb..24040c318 100755 --- a/test/units/testsuite-57.sh +++ b/test/units/testsuite-57.sh @@ -26,6 +26,33 @@ done systemctl stop testsuite-57-uphold.service +# Idea is this: +# 1. we start testsuite-57-retry-uphold.service +# 2. which through Uphold= starts testsuite-57-retry-upheld.service +# 3. which through Requires= starts testsuite-57-retry-fail.service +# 4. which fails as /tmp/testsuite-57-retry-fail does not exist, so testsuite-57-retry-upheld.service +# is no longer restarted +# 5. we create /tmp/testsuite-57-retry-fail +# 6. now testsuite-57-retry-upheld.service will be restarted since upheld, and its dependency will +# be satisfied + +rm -f /tmp/testsuite-57-retry-fail +systemctl start testsuite-57-retry-uphold.service + +while ! systemctl is-failed testsuite-57-retry-fail.service ; do + sleep .5 +done + +systemctl is-active testsuite-57-retry-upheld.service && { echo 'unexpected success'; exit 1; } + +touch /tmp/testsuite-57-retry-fail + +while ! systemctl is-active testsuite-57-retry-upheld.service ; do + sleep .5 +done + +systemctl stop testsuite-57-retry-uphold.service testsuite-57-retry-fail.service testsuite-57-retry-upheld.service + # Idea is this: # 1. we start testsuite-57-prop-stop-one.service # 2. which through Wants=/After= pulls in testsuite-57-prop-stop-two.service as well diff --git a/test/units/testsuite-60.sh b/test/units/testsuite-60.sh index a29364568..f390863ca 100755 --- a/test/units/testsuite-60.sh +++ b/test/units/testsuite-60.sh @@ -181,7 +181,7 @@ EOF # Trigger the mount ratelimiting cd "$(mktemp -d)" mkdir foo - for ((i = 0; i < 50; i++)); do + for _ in {1..50}; do mount --bind foo foo umount foo done @@ -225,7 +225,7 @@ EOF # shellcheck disable=SC2064 trap "rm -f /run/systemd/system/tmp-hoge.mount '$mount_mytmpfs'" RETURN - for ((i = 0; i < 10; i++)); do + for _ in {1..10}; do systemctl --no-block start tmp-hoge.mount sleep ".$RANDOM" systemctl daemon-reexec diff --git a/test/units/testsuite-63.sh b/test/units/testsuite-63.sh index 7ee7fc151..59a7b3208 100755 --- a/test/units/testsuite-63.sh +++ b/test/units/testsuite-63.sh @@ -3,6 +3,9 @@ set -ex set -o pipefail +# shellcheck source=test/units/assert.sh +. "$(dirname "$0")"/assert.sh + systemctl log-level debug # Test that a path unit continuously triggering a service that fails condition checks eventually fails with @@ -12,10 +15,10 @@ systemctl start test63.path touch /tmp/test63 # Make sure systemd has sufficient time to hit the trigger limit for test63.path. -sleep 2 +# shellcheck disable=SC2016 +timeout 30 bash -c 'while ! test "$(systemctl show test63.path -P ActiveState)" = failed; do sleep .2; done' test "$(systemctl show test63.service -P ActiveState)" = inactive test "$(systemctl show test63.service -P Result)" = success -test "$(systemctl show test63.path -P ActiveState)" = failed test "$(systemctl show test63.path -P Result)" = trigger-limit-hit # Test that starting the service manually doesn't affect the path unit. @@ -41,6 +44,42 @@ systemctl stop test63-glob.path test63-glob.service test "$(busctl --json=short get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/test63_2dglob_2eservice org.freedesktop.systemd1.Unit ActivationDetails)" = '{"type":"a(ss)","data":[]}' +# tests for issue https://github.com/systemd/systemd/issues/24577#issuecomment-1522628906 +rm -f /tmp/hoge +systemctl start test63-issue-24577.path +systemctl status -n 0 test63-issue-24577.path +systemctl status -n 0 test63-issue-24577.service || : +systemctl list-jobs +output=$(systemctl list-jobs --no-legend) +assert_not_in "test63-issue-24577.service" "$output" +assert_not_in "test63-issue-24577-dep.service" "$output" + +touch /tmp/hoge +systemctl status -n 0 test63-issue-24577.path +systemctl status -n 0 test63-issue-24577.service || : +systemctl list-jobs +output=$(systemctl list-jobs --no-legend) +assert_in "test63-issue-24577.service" "$output" +assert_in "test63-issue-24577-dep.service" "$output" + +# even if the service is stopped, it will be soon retriggered. +systemctl stop test63-issue-24577.service +systemctl status -n 0 test63-issue-24577.path +systemctl status -n 0 test63-issue-24577.service || : +systemctl list-jobs +output=$(systemctl list-jobs --no-legend) +assert_in "test63-issue-24577.service" "$output" +assert_in "test63-issue-24577-dep.service" "$output" + +rm -f /tmp/hoge +systemctl stop test63-issue-24577.service +systemctl status -n 0 test63-issue-24577.path +systemctl status -n 0 test63-issue-24577.service || : +systemctl list-jobs +output=$(systemctl list-jobs --no-legend) +assert_not_in "test63-issue-24577.service" "$output" +assert_in "test63-issue-24577-dep.service" "$output" + systemctl log-level info echo OK >/testok diff --git a/test/units/testsuite-64.sh b/test/units/testsuite-64.sh index c4406f381..9549e4770 100755 --- a/test/units/testsuite-64.sh +++ b/test/units/testsuite-64.sh @@ -156,9 +156,8 @@ helper_check_device_units() {( local i - for ((i = 0; i < 20; i++)); do - (( i == 0 )) || sleep .5 - + for i in {1..20}; do + (( i > 1 )) && sleep 0.5 if check_device_units 0 "$@"; then return 0 fi @@ -181,6 +180,8 @@ testcase_nvme_subsystem() { local expected_symlinks=( # Controller(s) /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef + /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef_16 + /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef_17 # Shared namespaces /dev/disk/by-path/pci-*-nvme-16 /dev/disk/by-path/pci-*-nvme-17 @@ -522,7 +523,7 @@ testcase_btrfs_basic() { echo "Single device: default settings" uuid="deadbeef-dead-dead-beef-000000000000" label="btrfs_root" - udevadm lock --device="${devices[0]}" mkfs.btrfs -L "$label" -U "$uuid" "${devices[0]}" + udevadm lock --device="${devices[0]}" mkfs.btrfs -f -L "$label" -U "$uuid" "${devices[0]}" udevadm wait --settle --timeout=30 "${devices[0]}" "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label" btrfs filesystem show helper_check_device_symlinks @@ -540,7 +541,7 @@ name="diskpart3", size=85M name="diskpart4", size=85M EOF udevadm wait --settle --timeout=30 /dev/disk/by-partlabel/diskpart{1..4} - udevadm lock --device="${devices[0]}" mkfs.btrfs -d single -m raid1 -L "$label" -U "$uuid" /dev/disk/by-partlabel/diskpart{1..4} + udevadm lock --device="${devices[0]}" mkfs.btrfs -f -d single -m raid1 -L "$label" -U "$uuid" /dev/disk/by-partlabel/diskpart{1..4} udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label" btrfs filesystem show helper_check_device_symlinks @@ -556,7 +557,7 @@ EOF --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs1 \ --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs2 \ --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs3 \ - mkfs.btrfs -M -d raid10 -m raid10 -L "$label" -U "$uuid" "${devices[@]}" + mkfs.btrfs -f -M -d raid10 -m raid10 -L "$label" -U "$uuid" "${devices[@]}" udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label" btrfs filesystem show helper_check_device_symlinks @@ -596,7 +597,7 @@ EOF --device=/dev/mapper/encbtrfs1 \ --device=/dev/mapper/encbtrfs2 \ --device=/dev/mapper/encbtrfs3 \ - mkfs.btrfs -M -d raid1 -m raid1 -L "$label" -U "$uuid" /dev/mapper/encbtrfs{0..3} + mkfs.btrfs -f -M -d raid1 -m raid1 -L "$label" -U "$uuid" /dev/mapper/encbtrfs{0..3} udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label" btrfs filesystem show helper_check_device_symlinks diff --git a/test/units/testsuite-65.sh b/test/units/testsuite-65.sh index ebe1f57b5..98527d652 100755 --- a/test/units/testsuite-65.sh +++ b/test/units/testsuite-65.sh @@ -6,6 +6,12 @@ set -eux # shellcheck source=test/units/assert.sh . "$(dirname "$0")"/assert.sh +runas() { + declare userid=$1 + shift + XDG_RUNTIME_DIR=/run/user/"$(id -u "$userid")" setpriv --reuid="$userid" --init-groups "$@" +} + systemctl log-level debug export SYSTEMD_LOG_LEVEL=debug @@ -42,6 +48,21 @@ systemd-analyze dot --require systemd-journald.service systemd-logind.service >/ systemd-analyze dot "systemd-*.service" >/dev/null (! systemd-analyze dot systemd-journald.service systemd-logind.service "*" bbb ccc) # dump +# this should be rate limited to 10 calls in 10 minutes for unprivileged callers +for _ in {1..10}; do + runas testuser systemd-analyze dump systemd-journald.service >/dev/null +done +(! runas testuser systemd-analyze dump >/dev/null) +# still limited after a reload +systemctl daemon-reload +(! runas testuser systemd-analyze dump >/dev/null) +# and a re-exec +systemctl daemon-reexec +(! runas testuser systemd-analyze dump >/dev/null) +# privileged call, so should not be rate limited +for _ in {1..10}; do + systemd-analyze dump systemd-journald.service >/dev/null +done systemd-analyze dump >/dev/null systemd-analyze dump "*" >/dev/null systemd-analyze dump "*.socket" >/dev/null @@ -138,6 +159,11 @@ systemd-analyze cat-config /etc/systemd/system.conf >/dev/null systemd-analyze cat-config systemd/system.conf systemd/journald.conf >/dev/null systemd-analyze cat-config systemd/system.conf foo/bar systemd/journald.conf >/dev/null systemd-analyze cat-config foo/bar +# security +systemd-analyze security +systemd-analyze security --json=off +systemd-analyze security --json=pretty | jq +systemd-analyze security --json=short | jq if [[ ! -v ASAN_OPTIONS ]]; then # check that systemd-analyze cat-config paths work in a chroot @@ -162,16 +188,13 @@ EOF set +e # Default behaviour is to recurse through all dependencies when unit is loaded -systemd-analyze verify --root=/tmp/img/ testfile.service \ - && { echo 'unexpected success'; exit 1; } +(! systemd-analyze verify --root=/tmp/img/ testfile.service) # As above, recurses through all dependencies when unit is loaded -systemd-analyze verify --recursive-errors=yes --root=/tmp/img/ testfile.service \ - && { echo 'unexpected success'; exit 1; } +(! systemd-analyze verify --recursive-errors=yes --root=/tmp/img/ testfile.service) # Recurses through unit file and its direct dependencies when unit is loaded -systemd-analyze verify --recursive-errors=one --root=/tmp/img/ testfile.service \ - && { echo 'unexpected success'; exit 1; } +(! systemd-analyze verify --recursive-errors=one --root=/tmp/img/ testfile.service) set -e @@ -201,8 +224,7 @@ systemd-analyze verify --recursive-errors=no /tmp/testfile2.service set +e # Non-zero exit status since all associated dependencies are recursively loaded when the unit file is loaded -systemd-analyze verify --recursive-errors=yes /tmp/testfile2.service \ - && { echo 'unexpected success'; exit 1; } +(! systemd-analyze verify --recursive-errors=yes /tmp/testfile2.service) set -e rm /tmp/testfile.service @@ -224,19 +246,15 @@ rm /tmp/.testfile.service # Alias a unit file's name on disk (see #20061) cp /tmp/testfile.service /tmp/testsrvc -systemd-analyze verify /tmp/testsrvc \ - && { echo 'unexpected success'; exit 1; } +(! systemd-analyze verify /tmp/testsrvc) systemd-analyze verify /tmp/testsrvc:alias.service # Zero exit status since the value used for comparison determine exposure to security threats is by default 100 systemd-analyze security --offline=true /tmp/testfile.service -set +e #The overall exposure level assigned to the unit is greater than the set threshold -systemd-analyze security --threshold=90 --offline=true /tmp/testfile.service \ - && { echo 'unexpected success'; exit 1; } -set -e +(! systemd-analyze security --threshold=90 --offline=true /tmp/testfile.service) # Ensure we print the list of ACLs, see https://github.com/systemd/systemd/issues/23185 systemd-analyze security --offline=true /tmp/testfile.service | grep -q -F "/dev/sda" @@ -727,19 +745,15 @@ systemd-analyze security --threshold=25 --offline=true \ --profile=strict \ --root=/tmp/img/ testfile.service -set +e # The trusted profile doesn't add any sanboxing options -systemd-analyze security --threshold=25 --offline=true \ +(! systemd-analyze security --threshold=25 --offline=true \ --security-policy=/tmp/testfile.json \ --profile=/usr/lib/systemd/portable/profile/trusted/service.conf \ - --root=/tmp/img/ testfile.service \ - && { echo 'unexpected success'; exit 1; } + --root=/tmp/img/ testfile.service) -systemd-analyze security --threshold=50 --offline=true \ +(! systemd-analyze security --threshold=50 --offline=true \ --security-policy=/tmp/testfile.json \ - --root=/tmp/img/ testfile.service \ - && { echo 'unexpected success'; exit 1; } -set -e + --root=/tmp/img/ testfile.service) rm /tmp/img/usr/lib/systemd/system/testfile.service diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh index c34cbaada..c049e8f9b 100755 --- a/test/units/testsuite-70.sh +++ b/test/units/testsuite-70.sh @@ -15,42 +15,42 @@ cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-uran 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 +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume # Check with wrong PCR tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 -/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } +(! /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1) # Enroll unlock with PCR+PIN policy systemd-cryptenroll --wipe-slot=tpm2 $img -env PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img -env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 +PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img +PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,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 - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } +(! PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=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' && \ [ -f "$(cryptsetup --help | sed -n -r 's/.*LUKS2 external token plugin path: (.*)\./\1/p')/libcryptsetup-token-systemd-tpm2.so" ]; then - env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=1 + 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; } + (! PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - headless=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; } +(! PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1) # Enroll unlock with PCR 0+7 systemd-cryptenroll --wipe-slot=tpm2 $img -env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img +PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 /usr/lib/systemd/systemd-cryptsetup detach test-volume @@ -119,7 +119,7 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \ # Invalidate PCR, decrypting should fail now tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 - systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" > /dev/null && { echo 'unexpected success'; exit 1; } + (! systemd-creds decrypt /tmp/pcrtestdata.encrypted - --tpm2-signature="/tmp/pcrsign.sig" > /dev/null) # Sign new PCR state, decrypting should work now. /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig2" @@ -146,8 +146,8 @@ if [ -e /usr/lib/systemd/systemd-measure ] && \ # After extending the PCR things should fail tpm2_pcrextend 11:sha256=0000000000000000000000000000000000000000000000000000000000000000 - SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; } - SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1 && { echo 'unexpected success'; exit 1; } + (! SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=0 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1) + (! SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE=1 /usr/lib/systemd/systemd-cryptsetup attach test-volume2 $img - tpm2-device=auto,tpm2-signature="/tmp/pcrsign.sig2",headless=1) # But once we sign the current PCRs, we should be able to unlock again /usr/lib/systemd/systemd-measure sign --current "${MEASURE_BANKS[@]}" --private-key="/tmp/pcrsign-private.pem" --public-key="/tmp/pcrsign-public.pem" --phase=: > "/tmp/pcrsign.sig3" @@ -170,6 +170,65 @@ systemd-run -p PrivateDevices=yes -p LoadCredentialEncrypted=testdata.encrypted: systemd-run -p PrivateDevices=yes -p SetCredentialEncrypted=testdata.encrypted:"$(cat /tmp/testdata.encrypted)" --pipe --wait systemd-creds cat testdata.encrypted | cmp - /tmp/testdata rm /tmp/testdata +# negative tests for cryptenroll + +# Prepare a new disk image +img_2="/var/tmp/file_enroll.txt" +truncate -s 20M $img_2 +echo -n password >/tmp/password +cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom $img_2 /tmp/password + +#boolean_arguments +(! systemd-cryptenroll --fido2-with-client-pin=false) + +(! systemd-cryptenroll --fido2-with-user-presence=f $img_2 /tmp/foo) + +(! systemd-cryptenroll --fido2-with-client-pin=1234 $img_2) + +systemd-cryptenroll --fido2-with-client-pin=false $img_2 + +(! systemd-cryptenroll --fido2-with-user-presence=1234 $img_2) + +systemd-cryptenroll --fido2-with-user-presence=false $img_2 + +(! systemd-cryptenroll --fido2-with-user-verification=1234 $img_2) + +(! systemd-cryptenroll --tpm2-with-pin=1234 $img_2) + +systemd-cryptenroll --fido2-with-user-verification=false $img_2 + +#arg_enroll_type +(! systemd-cryptenroll --recovery-key --password $img_2) + +(! systemd-cryptenroll --password --recovery-key $img_2) + +(! systemd-cryptenroll --password --fido2-device=auto $img_2) + +(! systemd-cryptenroll --password --pkcs11-token-uri=auto $img_2) + +(! systemd-cryptenroll --password --tpm2-device=auto $img_2) + +#arg_unlock_type +(! systemd-cryptenroll --unlock-fido2-device=auto --unlock-fido2-device=auto $img_2) + +(! systemd-cryptenroll --unlock-fido2-device=auto --unlock-key-file=/tmp/unlock $img_2) + +#fido2_cred_algorithm +(! systemd-cryptenroll --fido2-credential-algorithm=es512 $img_2) + +#tpm2_errors +(! systemd-cryptenroll --tpm2-public-key-pcrs=key $img_2) + +(! systemd-cryptenroll --tpm2-pcrs=key $img_2) + +#wipe_slots +(! systemd-cryptenroll --wipe-slot $img_2) + +(! systemd-cryptenroll --wipe-slot=10240000 $img_2) + +#fido2_multiple_auto +(! systemd-cryptenroll --fido2-device=auto --unlock-fido2-device=auto $img_2) + echo OK >/testok exit 0 diff --git a/test/units/testsuite-73.sh b/test/units/testsuite-73.sh index 4eae0f646..a5d801e93 100755 --- a/test/units/testsuite-73.sh +++ b/test/units/testsuite-73.sh @@ -206,8 +206,8 @@ restore_keymap() { wait_vconsole_setup() { local i ss - for ((i = 0; i < 20; i++)); do - if (( i != 0 )); then sleep .5; fi + for i in {1..20}; do + (( i > 1 )) && sleep 0.5 ss="$(systemctl --property SubState --value show systemd-vconsole-setup.service)" if [[ "$ss" == "exited" || "$ss" == "dead" || "$ss" == "condition" ]]; then return 0 @@ -393,6 +393,11 @@ XKBMODEL=pc105+inet" : >/failed +# Make sure the content of kbd-model-map is the one that the tests expect +# regardless of the version intalled on the distro where the testsuite is +# running on. +export SYSTEMD_KBD_MODEL_MAP=/usr/lib/systemd/tests/testdata/test-keymap-util/kbd-model-map + enable_debug test_locale test_vc_keymap diff --git a/test/units/testsuite-74.cgls.sh b/test/units/testsuite-74.cgls.sh index 120570c9c..9268f42ba 100755 --- a/test/units/testsuite-74.cgls.sh +++ b/test/units/testsuite-74.cgls.sh @@ -14,7 +14,8 @@ systemd-cgls --cgroup-id=no systemd-cgls /system.slice/systemd-journald.service systemd-cgls /system.slice/systemd-journald.service /init.scope systemd-cgls /sys/fs/cgroup/system.slice/systemd-journald.service /init.scope -(cd /sys/fs/cgroup/init.scope && systemd-cgls) +[[ -d /sys/fs/cgroup/init.scope ]] && init_scope="init.scope" || init_scope="systemd/init.scope" +(cd "/sys/fs/cgroup/$init_scope" && systemd-cgls) systemd-cgls --unit=systemd-journald.service # There's most likely no user session running, so we need to create one systemd-run --user --wait --pipe -M testuser@.host systemd-cgls --user-unit=app.slice diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh index 1f1a3bb4c..eb24b70b8 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/testsuite-75.sh @@ -31,7 +31,7 @@ monitor_check_rr() ( # Test for resolvectl, resolvconf systemctl unmask systemd-resolved.service -systemctl start systemd-resolved.service +systemctl enable --now systemd-resolved.service systemctl service-log-level systemd-resolved.service debug ip link add hoge type dummy ip link add hoge.foo type dummy diff --git a/units/systemd-coredump.socket b/units/systemd-coredump.socket index 565374698..a2d457fc0 100644 --- a/units/systemd-coredump.socket +++ b/units/systemd-coredump.socket @@ -11,7 +11,7 @@ Description=Process Core Dump Socket Documentation=man:systemd-coredump(8) DefaultDependencies=no -Before=shutdown.target +Before=shutdown.target systemd-sysctl.service Conflicts=shutdown.target [Socket] diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in index 75652e626..9ac56baf4 100644 --- a/units/systemd-hostnamed.service.in +++ b/units/systemd-hostnamed.service.in @@ -12,7 +12,7 @@ Description=Hostname Service Documentation=man:systemd-hostnamed.service(8) Documentation=man:hostname(5) Documentation=man:machine-info(5) -Documentation=man:org.freedesktop.resolve1(5) +Documentation=man:org.freedesktop.hostname1(5) [Service] BusName=org.freedesktop.hostname1 diff --git a/units/systemd-networkd-wait-online@.service.in b/units/systemd-networkd-wait-online@.service.in index 2fae26d1c..b7a1e409f 100644 --- a/units/systemd-networkd-wait-online@.service.in +++ b/units/systemd-networkd-wait-online@.service.in @@ -10,6 +10,7 @@ [Unit] Description=Wait for Network Interface %i to be Configured Documentation=man:systemd-networkd-wait-online.service(8) +ConditionCapability=CAP_NET_ADMIN DefaultDependencies=no Conflicts=shutdown.target BindsTo=systemd-networkd.service diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index d15129e7f..8b5dd0bbf 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -10,12 +10,13 @@ [Unit] Description=Network Configuration Documentation=man:systemd-networkd.service(8) +Documentation=man:org.freedesktop.network1(5) ConditionCapability=CAP_NET_ADMIN DefaultDependencies=no # systemd-udevd.service can be dropped once tuntap is moved to netlink After=systemd-networkd.socket systemd-udevd.service network-pre.target systemd-sysusers.service systemd-sysctl.service -Before=network.target multi-user.target shutdown.target -Conflicts=shutdown.target +Before=network.target multi-user.target shutdown.target initrd-switch-root.target +Conflicts=shutdown.target initrd-switch-root.target Wants=systemd-networkd.socket network.target [Service] diff --git a/units/systemd-oomd.service.in b/units/systemd-oomd.service.in index 9f248e2ba..c138f5eef 100644 --- a/units/systemd-oomd.service.in +++ b/units/systemd-oomd.service.in @@ -10,6 +10,7 @@ [Unit] Description=Userspace Out-Of-Memory (OOM) Killer Documentation=man:systemd-oomd.service(8) +Documentation=man:org.freedesktop.oom1(5) DefaultDependencies=no Before=multi-user.target shutdown.target Conflicts=shutdown.target diff --git a/units/systemd-oomd.socket b/units/systemd-oomd.socket index 47cd0e755..70eb6b7bc 100644 --- a/units/systemd-oomd.socket +++ b/units/systemd-oomd.socket @@ -11,7 +11,13 @@ Description=Userspace Out-Of-Memory (OOM) Killer Socket Documentation=man:systemd-oomd.service(8) DefaultDependencies=no -Before=sockets.target +Before=sockets.target shutdown.target +Conflicts=shutdown.target +ConditionControlGroupController=v2 +ConditionControlGroupController=memory +ConditionPathExists=/proc/pressure/cpu +ConditionPathExists=/proc/pressure/io +ConditionPathExists=/proc/pressure/memory [Socket] ListenStream=/run/systemd/oom/io.system.ManagedOOM diff --git a/units/systemd-portabled.service.in b/units/systemd-portabled.service.in index e0afe9eab..ab660ce36 100644 --- a/units/systemd-portabled.service.in +++ b/units/systemd-portabled.service.in @@ -10,6 +10,7 @@ [Unit] Description=Portable Service Manager Documentation=man:systemd-portabled.service(8) +Documentation=man:org.freedesktop.portable1(5) RequiresMountsFor=/var/lib/portables [Service] diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in index 621fe3422..c54852695 100644 --- a/units/systemd-resolved.service.in +++ b/units/systemd-resolved.service.in @@ -16,8 +16,8 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-resolver DefaultDependencies=no After=systemd-sysusers.service -Before=sysinit.target network.target nss-lookup.target shutdown.target -Conflicts=shutdown.target +Before=sysinit.target network.target nss-lookup.target shutdown.target initrd-switch-root.target +Conflicts=shutdown.target initrd-switch-root.target Wants=nss-lookup.target [Service] diff --git a/units/systemd-sysext.service b/units/systemd-sysext.service index 254de2b62..f8c26f5fb 100644 --- a/units/systemd-sysext.service +++ b/units/systemd-sysext.service @@ -20,7 +20,7 @@ ConditionDirectoryNotEmpty=|/usr/lib/extensions DefaultDependencies=no After=local-fs.target -Before=sysinit.target systemd-tmpfiles.service +Before=sysinit.target systemd-tmpfiles-setup.service Conflicts=shutdown.target initrd-switch-root.target Before=shutdown.target initrd-switch-root.target diff --git a/units/systemd-time-wait-sync.service.in b/units/systemd-time-wait-sync.service.in index 8ef3db0d5..d14491a01 100644 --- a/units/systemd-time-wait-sync.service.in +++ b/units/systemd-time-wait-sync.service.in @@ -11,7 +11,7 @@ Description=Wait Until Kernel Time Synchronized Documentation=man:systemd-time-wait-sync.service(8) -# Note that this tool doesn't need CAP_SYS_TIME itself, but it's primary +# Note that this tool doesn't need CAP_SYS_TIME itself, but its primary # usecase is to run in conjunction with a local NTP service such as # systemd-timesyncd.service, which is conditioned this way. There might be # niche usecases where running this service independently is desired, but let's diff --git a/units/user@.service.in b/units/user@.service.in index 1660de032..1735e8e6e 100644 --- a/units/user@.service.in +++ b/units/user@.service.in @@ -10,7 +10,7 @@ [Unit] Description=User Manager for UID %i Documentation=man:user@.service(5) -After=user-runtime-dir@%i.service dbus.service +After=user-runtime-dir@%i.service dbus.service systemd-oomd.service Requires=user-runtime-dir@%i.service IgnoreOnIsolate=yes